Skip to content

Instantly share code, notes, and snippets.

@rubencodes
Created November 24, 2021 14:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rubencodes/b0a61efea0fd53676efb73c957ac5808 to your computer and use it in GitHub Desktop.
Save rubencodes/b0a61efea0fd53676efb73c957ac5808 to your computer and use it in GitHub Desktop.
TypeScript Currying
type AnyArray = any[];
type AnyArrayWithItems = [any, ...any];
type AnyFunction<Arguments extends any[] = any[]> = (...args: Arguments) => any;
// The type of the first item in an array.
// Input: `[1, 2, 3]`
// Output: `1`
type Head<SomeArray extends AnyArray> = 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<SomeArray extends AnyArray> = AnyFunction<SomeArray> 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 extends AnyArray> = 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<SomeArray> extends Num ? true : false;
// A curried version of the function type.
// Input: `(x, y) => z`
// Output: `(x) => (y) => z`.
type Curried<Func extends AnyFunction> = (
arg: Head<Parameters<Func>>,
) => HasLength<Parameters<Func>, 1> extends true
? ReturnType<Func>
: Curried<(...args: Tail<Parameters<Func>>) => ReturnType<Func>>;
declare function curry<Func extends AnyFunction>(func: Func): Curried<Func>;
const toCurry = (name: string, age: number, single: boolean) => true;
curry(toCurry)("Ruben")(21)(true); // true
curry(toCurry)("Foo")("Bar")("Baz"); // TypeError
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment