type GenericFunction = (...x: never[]) => unknown; type Assume = T extends U ? T : U; abstract class TypeFunc { readonly _1?: unknown; new: GenericFunction; } type Apply = ReturnType< (F & { readonly _1: _1; })["new"] >; class Z { private constructor() {} static z(): Z { return new Z(); } } class S> { public prev: (_: Prev) => Prev; private constructor() {} static s>(): S { return new S(); } } type Nat = Z | S; interface NatElim, SCase extends TypeFunc> extends TypeFunc { _unused: (_1: ZCase, _2: SCase) => never; new: (arg: Assume) => Apply; } interface ConstNat extends TypeFunc { new: (_: unknown) => Nat; } interface DoubleSuc extends TypeFunc { new: (arg: Assume) => S>; } interface DoubleNat extends TypeFunc { new: ( arg: Assume ) => Apply, typeof arg>; } type Two = S>; const realThree: S>> = S.s(); const realFour: S>>> = S.s(); function isFour>(_: F) {} isFour(realThree); isFour(realFour); ///// type Length = T extends { length: infer L } ? L : never; type BuildTuple = T extends { length: L; } ? T : BuildTuple; type Add = Length< [...BuildTuple, ...BuildTuple] >; type Equals = { eq: [T1, T2] }; type Seven = Add<3, 4>; // 7 function isSeven(s: Seven) {} isSeven(6); isSeven(7); /// class Eq { private a: (_: A) => A; private b: (_: B) => B; private constructor() {} static refl(): Eq { return new Eq(); } } function isEqual1(_: Eq<3, 3>) {} isEqual1(Eq.refl()); function isEqual2(_: Eq<3, 4>) {} isEqual2(Eq.refl()); function isEqual3(_: Eq, 7>) {} isEqual3(Eq.refl()); function isEqual4(_: Eq, 8>) {} isEqual4(Eq.refl()); /// type Commutative = Eq, Add>; function comm(): Commutative { return Eq.refl(); }