Skip to content

Instantly share code, notes, and snippets.

@Oaphi
Last active July 16, 2021 18:19
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 Oaphi/3013417d6aebaf4050a7d3bcb9fe0ac9 to your computer and use it in GitHub Desktop.
Save Oaphi/3013417d6aebaf4050a7d3bcb9fe0ac9 to your computer and use it in GitHub Desktop.
Useful tuple utility types
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>;
@Oaphi
Copy link
Author

Oaphi commented Feb 11, 2021

Note that $ in template literal types are escaped (seems like there is a highlighting bug). Unescape them in your code!

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