Skip to content

Instantly share code, notes, and snippets.

@tkburns
Last active December 13, 2021 02:47
Show Gist options
  • Save tkburns/23e58e6b1d4db1a5fbd6a7444a1c307c to your computer and use it in GitHub Desktop.
Save tkburns/23e58e6b1d4db1a5fbd6a7444a1c307c to your computer and use it in GitHub Desktop.
Assorted type utilities for Typescript

Assorted Type Utilities

A collection of assorted type utilities for Typescript.

export type MapByType<Ts extends { type: string }> = {
[K in Ts['type']]: Extract<Ts, { type: K }>;
};
export type UnionToIntersection<T> =
(T extends unknown ? (x: T) => unknown : never) extends
(x: infer R) => unknown ? R : never;
import type { UnionToIntersection } from './01-misc';
export type Head<L extends unknown[]> =
L extends [infer H, ...unknown[]] ? H : // tuple with >= 1 element
L extends [] ? never : // empty tuple
L[number] | undefined; // list with unknown length (eg x[])
export type Tail<L extends unknown[]> =
L extends [head: unknown, ...tail: infer T] ? T : // tuple with >= 1 element
L extends [] ? [] : // empty tuple
L; // list with unknown length (eg x[])
export type Last<L extends unknown[]> =
L extends Tail<L> ? (L[number] | undefined) : // list of unknown length (not a tuple)
L extends [] ? never : // empty tuple
L extends [unknown] ? Head<L> : // 1-element tuple
Last<Tail<L>>; // tuple with >= 2 elements
export type Prepend<L extends unknown[], T> = [T, ...L];
export type Concat<L extends unknown[], M extends unknown[]> =
L extends [] ? M : // empty tuple
L extends Tail<L> ? (L[number] | M[number])[] : // list of unknown length (not a tuple)
[Head<L>, ...Concat<Tail<L>, M>]; // tuple with >= 2 elements
/*
(wip) returns a tuple type that is assignable to all unions in the provided type
SatisfyAll<[string, {a: 'a'}] | [string, {b: 'b'}]> ~= [string, {a: 'a'} & {b: 'b'}]
Note - this does not handle the case when one type in the union is a subtype of another (the union immediately swallows the subtype)
*/
export type SatisfyAll<L extends unknown[]> =
[L] extends [Tail<L>] ? L[number][] :
[L] extends [[]] ? never :
[UnionToIntersection<Exclude<Head<L>, undefined>>, ...SatisfyAll<Tail<L>>];
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment