type $If<X: boolean, Then, Else = empty> = $Call< & ((true, Then, Else) => Then) & ((false, Then, Else) => Else), X, Then, Else, >; type $Not<X: boolean> = $If<X, false, true>; type $And<X: boolean, Y: boolean> = $If<X, Y, false>; type $Or<X: boolean, Y: boolean> = $If<X, true, Y>; type $Gte<X, Y> = $Call< & ($Subtype<X> => true) & (mixed => false), Y, >; //// declare var a: $Gte<number, string>; /* error 1 */ (a: true); /* ok */ (a: false); declare var b: $Gte<number, number>; /* ok */ (b: true); /* error 2 */ (b: false); declare var c: $If<true, 1, 2>; /* ok */ (c: 1); /* error 3 */ (c: 2); declare var d: $If<false, 1, 2>; /* error 4 */ (d: 1); /* ok */ (d: 2); //// declare var e: $If<$Gte<number, string>, 1, 2>; /* error 5 */ (e: 1); /* ok */ (e: 2); declare var f: $If<$Gte<number, number>, 1, 2>; /* ok */ (f: 1); /* error 6 */ (f: 2); //// type IsNumber<X> = $Gte<number, X>; type NumberTo12<X> = $If<IsNumber<X>, 1, 2>; declare var g: NumberTo12<string>; /* error 7 */ (g: 1); /* ok */ (g: 2); declare var h: NumberTo12<number>; /* ok */ (h: 1); /* error 8 */ (h: 2);