Skip to content

Instantly share code, notes, and snippets.

@cefn
Created September 6, 2023 13:44
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 cefn/d552ec3ef0b6918b5be80c9cc42cd5b9 to your computer and use it in GitHub Desktop.
Save cefn/d552ec3ef0b6918b5be80c9cc42cd5b9 to your computer and use it in GitHub Desktop.
Type-safe tuple composition from literal numbers
/** The union of the types of members of array `Arr` */
export type MemberOf<Arr extends readonly unknown[]> = Arr[number];
// from https://stackoverflow.com/a/65914848/2257198
type Tuple<T, N extends number, A extends unknown[] = []> = A extends { length: N } ? A : Tuple<T, N, [...A, T]>;
export function composeTuple<Item, Length extends number, LengthCast = [...Item[]]>(item: Item, length: Length) {
return Array.from({ length }).map(() => item) as LengthCast;
}
export function composeOneOrMore<Item, Length extends number>(item: Item, length: Length) {
if (length < 1) {
throw new Error(`Cannot create tuple of length ${length}`);
}
return composeTuple<Item, Length, Tuple<Item, Length, [Item]>>(item, length);
}
export function hasLength<A extends [...unknown[]], Length extends number>(
array: A,
length: Length,
): array is A & Tuple<MemberOf<A>, Length> {
return array.length === length;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment