Skip to content

Instantly share code, notes, and snippets.

@willfrew
Created August 15, 2018 12:53
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save willfrew/6c6de7225c0cbec4545631efa4478193 to your computer and use it in GitHub Desktop.
Save willfrew/6c6de7225c0cbec4545631efa4478193 to your computer and use it in GitHub Desktop.
Fun with tuple types in Typescript 3.0
type Head<T extends unknown[]> = T[0];
type FnWithArgs<T extends unknown[]> = (...args: T) => void;
type TailArgs<T> = T extends (x: unknown, ...args: infer T) => unknown ? T : never;
type Tail<T extends unknown[]> = TailArgs<FnWithArgs<T>>;
// Lol
type Decr<T extends number> =
T extends 10 ? 9 :
T extends 9 ? 8 :
T extends 8 ? 7 :
T extends 7 ? 6 :
T extends 6 ? 5 :
T extends 5 ? 4 :
T extends 4 ? 3 :
T extends 2 ? 1 :
T extends 1 ? 0 :
never;
type Length<T extends unknown[]> = T['length'];
type Last<T extends unknown[]> = T[Decr<Length<T>>];
type Tuple = [number, string, boolean, string, { a: number }];
type LengthT = Length<Tuple>; // 5
type LastT = Last<Tuple>; // { a: number }
type HeadT = Head<Tuple>; // string
type TailT = Tail<Tuple>; // [string, boolean, string, { a: number }]
@tokland
Copy link

tokland commented Feb 16, 2020

Cool, thx for sharing. A couple of issues:

  • TailArgs should not reuse T, it does not work as it is.
  • HeadT should be // number

@flappyBug
Copy link

With TypeScript 4.0 variadic tuple types, Tail can be simplified as:

type Tail<T extends unknown[]> = T extends [unknown, ...infer TailType] ? TailType : never;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment