import { assert } from './errors.js'; export { AnyFunction, Tuple, TupleN, AnyTuple, TupleMap, Subclass, Get }; type AnyFunction = (...args: any) => any; type Tuple = [T, ...T[]] | []; type AnyTuple = Tuple; type TupleMap, B> = [ ...{ [i in keyof T]: B; } ]; const Tuple = { map, B>(tuple: T, f: (a: T[number]) => B): TupleMap { return tuple.map(f) as any; }, }; /** * tuple type that has the length as generic parameter */ type TupleN = N extends N ? number extends N ? [...T[]] // N is not typed as a constant => fall back to array : [...TupleRec] : never; const TupleN = { map, B>(tuple: T, f: (a: T[number]) => B): TupleMap { return tuple.map(f) as any; }, fromArray(n: N, arr: T[]): TupleN { assert(arr.length === n, `Expected array of length ${n}, got ${arr.length}`); return arr as any; }, hasLength(n: N, tuple: T[]): tuple is TupleN { return tuple.length === n; }, }; type TupleRec = R['length'] extends N ? R : TupleRec; // classes type Subclass any> = (new ( ...args: any ) => InstanceType) & { [K in keyof Class]: Class[K]; } & { prototype: InstanceType }; /** * helper to get property type from an object, in place of `T[Key]` * * assume `T extends { Key?: Something }`. * if we use `Get` instead of `T[Key]`, we allow `T` to be inferred _without_ the `Key` key, * and thus retain the precise type of `T` during inference */ type Get = T extends { [K in Key]: infer _Value } ? _Value : undefined;