0011 · Tuple to Object
0011 · Tuple to Object
Problem
Given an array, transform it into an object type and the key/value must be in the provided array.
const tuple = ['tesla', 'model 3', 'model X', 'model Y'] as const
type result = TupleToObject<typeof tuple>
// expected { 'tesla': 'tesla', 'model 3': 'model 3', 'model X': 'model X', 'model Y': 'model Y' }Solution
type TupleToObject<T extends readonly (string | number | symbol)[]> = {
[K in T[number]]: K
}Explanation
The key insight here is T[number] — indexing a tuple/array with number produces a union of all its element types.
Step by step:
T extends readonly (string | number | symbol)[]— constrainsTto a readonly tuple whose elements can be used as object keys (string, number, or symbol)T[number]— produces a union of all element types inT. For['tesla', 'model 3'], this gives'tesla' | 'model 3'[K in T[number]]— iterates over each valueKfrom the union: K— the value type is the same as the key (each key maps to itself)
Why readonly?
The as const assertion (used in the test cases) makes the tuple readonly. Without extends readonly ...[], TypeScript would reject readonly tuples as input.
Why string | number | symbol?
These are the only types valid as object keys in TypeScript. Adding this constraint means TypeScript can confirm that each K is a valid key for the resulting object type.
Key concepts:
- Indexed Access Types —
T[number]extracts all element types as a union - Mapped Types
as const— narrows literal types and makes tuples readonly
Tips
T[number] works because arrays/tuples have numeric indices. Indexing with number asks TypeScript: "what type can I get when I index this array with any number?" — and the answer is the union of all element types.
中文解析
核心思路:
将元组转换为对象类型的关键在于 T[number] 技巧——用 number 索引元组/数组类型,可以得到所有元素类型的联合类型。
// 解法
type TupleToObject<T extends readonly (string | number | symbol)[]> = {
[K in T[number]]: K
// T[number] 将元组元素展开为联合类型,再用映射类型遍历
}逐步分析:
T extends readonly (string | number | symbol)[]— 约束T为只读元组,且元素必须是合法的对象键类型T[number]— 获取元组所有元素的联合类型。例如['a', 'b'][number]→'a' | 'b'[K in T[number]]— 遍历联合类型中的每个值K: K— 键和值相同(自映射)
为什么需要 readonly?as const 断言会让元组变成 readonly,如果约束不包含 readonly,TypeScript 就会拒绝接受 as const 元组作为参数。
考察知识点:
- 索引访问类型(Indexed Access Types)—
T[number] - 映射类型(Mapped Types)
as const断言与字面量类型
