Задачка: получить в типо-параметре дженерик функции кортеж его аргумента вот так
const test1 = tuple([1, '2', false]) // [number, string, boolean]
Решаем наивным подходом: Приходит понимание что трактовать аргумент можно двояко — и как гомогенный(одного типа) массив и как кортеж
declare function tupleNaive<T extends ReadonlyArray<any>>(elements: T): T;
tupleWrong([1,'2',false]) // (string | number | boolean)[]
tupleWrong([1, 2]) // number[]
tupleWrong([]) // never[]
Попытка номер 2 (
...elements: T) — сигнатура функции поменяласьdeclare function tupleDisctruction<T extends ReadonlyArray<any>>(...elements: T): T;
tupleDisctruction(1, '2', false) // [number, string, boolean]
tupleDisctruction(1, 2) // [number, number]
tupleDisctruction() // []
Вспоминаю про
const для вывода литералов (<const T ...): Почти, но не тоdeclare function tupleConst<const T extends ReadonlyArray<any>>(elements: T): T;
tupleConst([1, '2', false]) // readonly [1, '2', false]
tupleConst([1, 2]) // readonly [1, 2]
tupleConst([]) // readonly []
Натыкаюсь в исходниках какой-то библиотеки для type-level ts на такой трюк (
<T extends ReadonlyArray<any> | readonly [any]>)declare function tuple<T extends ReadonlyArray<any> | readonly [any]>(elements: T): T;
tuple([1, '2', false]) // [number, string, boolean]
tuple([1, 2]) // [number, number]
tuple([]) // []
Оказывается если в ограничениях типо-аргумента есть хоть один кортеж - то он будет трактоваться как кортеж 🤯
https://github.com/microsoft/TypeScript/issues/27179#issuecomment-422911925