Last active
June 19, 2018 15:51
-
-
Save eps1lon/0a7288d4e5669dbbbe79f1b6624690a7 to your computer and use it in GitHub Desktop.
Tuple type inference in TypeScript
This file contains 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
// The problem, playground: https://bit.ly/2t9gDij | |
const getFirst = (arg: [number, number]) => arg[0]; | |
const getSecond = (arg: [number, number]) => arg[1]; | |
const foo = [1, 2]; | |
const foo_tuple = foo as Tuple2b<typeof foo>; | |
const firstBad = getFirst(foo); // $ExpectError | |
// the "solution" | |
/** | |
* first iteration with ts 2.8 conditional types. Turs out | |
* you don't need those. | |
*/ | |
type Tuple2<T> = T extends Array<infer U> ? [U, U] : never; | |
/** | |
* casts arrays to tuples | |
* remember that there is no difference between T[0] and T[n] | |
* for arrays | |
*/ | |
type Tuple2b<T extends Array<any>> = [T[0], T[0]]; | |
/** | |
* returns an actual tuple (no more or less elements) | |
* creates a new array | |
* costs new array call and array.prototype.length call | |
*/ | |
const asTupleActual = <T>(list: T[]): [T, T] => { | |
if (list.length !== 2) throw new Error('not a tuple'); | |
return [list[0], list[1]]; | |
} | |
/** | |
* identity function with runtime check | |
* costs array.prototype.length call | |
*/ | |
const asTupleSafe = <T>(list: T[]): [T, T] => { | |
if (list.length !== 2) throw new Error('not a tuple'); | |
return list as [T, T]; | |
} | |
/** | |
* just a typecast, can return 1 or fewer elements | |
*/ | |
const asTupleUnsafe = <T>(list: T[]): [T, T] => { | |
return list as [T, T]; | |
} | |
const firstGoodA = getFirst(foo as Tuple2b<typeof foo>); | |
const firstGoodB = getFirst(foo_tuple); | |
const firstGoodC = getFirst(asTupleActual(foo)); | |
const firstGoodD = getFirst(asTupleSafe(foo)); | |
// can be undefined at runtime | |
const firstGoodE = getFirst(asTupleUnsafe(foo)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment