type AnyArray = any[]; type AnyArrayWithItems = [any, ...any]; type AnyFunction = (...args: Arguments) => any; // The type of the first item in an array. // Input: `[1, 2, 3]` // Output: `1` type Head = SomeArray extends AnyArrayWithItems ? SomeArray[0] : never; // The type of an array after removing the first element. // Input: `[1, 2, 3]` // Output: `[2, 3]` type Tail = AnyFunction extends ( _: any, ...args: infer Remainder ) => any ? Remainder : never; // A type representing the length of an array. // Input: `[1, 2, 3]` // Output: `3` type Length = SomeArray["length"]; // A true type if an array is of a certain length, false otherwise. // Input: `[1, 2, 3]`, `3` // Output: `true` type HasLength< SomeArray extends AnyArray, Num extends number, > = Length extends Num ? true : false; // A curried version of the function type. // Input: `(x, y) => z` // Output: `(x) => (y) => z`. type Curried = ( arg: Head>, ) => HasLength, 1> extends true ? ReturnType : Curried<(...args: Tail>) => ReturnType>; declare function curry(func: Func): Curried; const toCurry = (name: string, age: number, single: boolean) => true; curry(toCurry)("Ruben")(21)(true); // true curry(toCurry)("Foo")("Bar")("Baz"); // TypeError