Last active
July 16, 2021 18:19
-
-
Save Oaphi/3013417d6aebaf4050a7d3bcb9fe0ac9 to your computer and use it in GitHub Desktop.
Useful tuple utility types
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type Indices<A> = Exclude<keyof A, keyof any[]>; | |
type valueAtIndexToNever<T extends any[], I extends number> = { | |
[ P in keyof T ] : P extends Indices<T> ? | |
P extends `\${I}` ? never : T[P] : | |
T[P] | |
} | |
type test1 = valueAtIndexToNever<[1,2,3],1>; //[1, never, 3]; | |
type IndicesNum<A extends any[]> = Exclude< | |
Partial<T>["length"], | |
T["length"] | |
>; | |
type test2 = Indices<[1,2,3]>; //"0" | "1" | "2" | |
type GenerateIndicesUpTo<N extends number, A extends any[] = []> = { | |
0: Indices<A>, | |
1: GenerateIndicesUpTo<N, [ ...A, any ]> | |
}[ A["length"] extends N ? 0 : 1 ]; | |
//max depth is 44 recursions until "Type instantiation is excessively deep and possibly infinite" is thrown | |
type test3 = GenerateIndicesUpTo<44>; //"0" | "1" ... "43" | |
type GenTuple<E extends any, L extends number, A extends any[] = []> = A["length"] extends L ? A : GenTuple<E, L, [ ...A, E ] >; | |
type testGen = GenTuple<number, 44>; | |
type filterTypeFromTuple<A extends any[], T = never> = { | |
[ P in keyof A as A[P] extends T ? never : P ] : A[P] | |
}; | |
//same except for index 2 | |
type test4 = filterTypeFromTuple<[1,never,2]>; | |
type UndefIndex<T extends any[] | readonly any[], I extends number> = { | |
[P in keyof T]: P extends Indices<T> | |
? P extends `\${I}` | |
? undefined | |
: T[P] | |
: T[P]; | |
}; | |
type FilterUndefined<T extends any[]> = T extends [] | |
? [] | |
: T extends [infer H, ...infer R] | |
? H extends undefined | |
? FilterUndefined<R> | |
: [H, ...FilterUndefined<R>] | |
: T; | |
//version that works with readonly tuples | |
type FilterReadonlyUndefined<T extends readonly any[]> = T extends readonly [] | |
? readonly [] | |
: T extends readonly [infer H, ...infer R] | |
? H extends undefined | |
? FilterReadonlyUndefined<R> | |
: [H, ...FilterReadonlyUndefined<R>] | |
: T; | |
type SpliceTuple<T extends any[], I extends number> = FilterUndefined< | |
UndefIndex<T, I> | |
>; | |
type SpliceReadonlyTuple<T extends readonly any[], I extends number> = FilterReadonlyUndefined<UndefIndex<T,I>>; | |
type a = SpliceTuple<[1,2,3], 0>; //[2,3] | |
type b = SpliceTuple<[1,2,3], 1>; //[1,3] | |
type c = SpliceTuple<[1,2,3], 2>; //[1,2] | |
type d = SpliceTuple<[1,2,3], 3>; //[1,2,3] | |
type SpliceGrid<G extends any[][], I extends number> = { | |
[ P in keyof G ] : G[P] extends any[] ? SpliceTuple<G[P], I> : never; | |
} | |
type test5 = SpliceGrid<[[1,2,3],[4,5,6]],1>; //[[1,3],[4,6]] | |
type GridToColumnTuple<G extends any[][], I extends number> = { | |
[ P in keyof G ] : G[P] extends any[] ? G[P][I] : never; | |
}; | |
type test6 = GridToColumnTuple<[[1,2],[3,4]], 1>; //[2,4] | |
type MergeTuples<A extends any[], B extends any[]> = [ ...A, ...B ]; | |
type test7 = MergeTuples<[1,2,3], [4,5,6]>; | |
type Replace<A extends any[], I extends number, T> = { | |
[ P in keyof A ] : P extends `\${I}` ? T : A[P]; | |
} | |
type test8 = Replace<[1,2,3], 1, "placeholder">; //[1, "placeholder", 3]; | |
type test9 = Replace<[3,4,5],22,null>; //[3, 4, 5] | |
type AtIndex<A extends any[], I extends number = 0> = Pick<A, I>[I]; | |
type test10 = AtIndex<[1,2,false],10>; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Note that
$
in template literal types are escaped (seems like there is a highlighting bug). Unescape them in your code!