В TS есть 2 варианта итерироваться по частям юнион типа - это условные типы и итерация по ключам, притом итерация по ключам ограничена типом
number | string | symbol
Условные типы проверяют условие для каждого варианта юниона, а значит позволяют трансформировать каждый из вариантов по отдельности:
type MyFunc = <N extends string>() => (N extends string ? Field<N> : never)[];
но возвращаемый тип так же будет юнионом:
({ name: "town" } | { name: "city" })[]
Сделать кортежный тип из юниона не выйдет, так как в юнионе не определен порядок, тип
"town" | "city"
это тоже самое, что и тип
"city" | "town"
.
Но можно сделать кортеж из кортежа:
type MyFunc = <N extends string[]>() => {
[K in keyof N]: N[K] extends string ? Field<N[K]> : never;
};
myFunc<["town", "city"]>()
Ну и в реальном коде гораздо удобнее, когда дженерик выводится из аргументов, а для того что бы TS сам вывел кортежный тип из абстрактного массива, данный массив нужно помечать
as const
, что так же делает его readonly массивом. Но принимать аргументы через readonly там где нам не нужно их мутирорвать - это вообще хорошая практика. Полный пример будет выглядеть так:
https://www.typescriptlang.org/play?#code/C4TwDgpg...