Tuple to Nested Object
问题描述
给定一个只包含字符串类型的元组类型 T
和一个类型 U
,递归地构建一个对象。
type a = TupleToNestedObject<['a'], string> // {a: string}
type b = TupleToNestedObject<['a', 'b'], number> // {a: {b: number}}
type c = TupleToNestedObject<[], boolean> // boolean. 如果元组为空,返回泛型 U 即可。
// ============= Test Cases =============
import type { Equal, Expect } from './test-utils'
type cases = [
Expect<Equal<TupleToNestedObject<['a'], string>, { a: string }>>,
Expect<Equal<TupleToNestedObject<['a', 'b'], number>, { a: { b: number } }>>,
Expect<Equal<TupleToNestedObject<['a', 'b', 'c'], boolean>, { a: { b: { c: boolean } } }>>,
Expect<Equal<TupleToNestedObject<[], boolean>, boolean>>
]
// ============= Your Code Here =============
// 答案1
type TupleToNestedObject<T, U> = T extends [infer F, ...infer R]
? {
[K in F & string]: TupleToNestedObject<R, U>
}
: U
// 答案2
type TupleToNestedObject<T extends readonly PropertyKey[], U> = T extends readonly [
infer K,
...infer R extends readonly PropertyKey[]
]
? { [P in K as P extends PropertyKey ? P : never]: TupleToNestedObject<R, U> }
: U
// 答案3
type TupleToNestedObject<T extends readonly PropertyKey[], U> = T extends readonly [
infer K extends PropertyKey,
...infer R extends readonly PropertyKey[]
]
? { [P in K]: TupleToNestedObject<R, U> }
: U
这里从题目可知,第一个泛型 T
应该是个元组,并且元组中的每一项都会是对象的 key
类型,也就是 string | number | symbol
,也可以用内置类型 PropertyKey
,所以泛型约束应该是T extends readonly PropertyKey[]
, 其次不难看出需要用到递归来判断,我们的思路是,从元组中一个一个的取出类型,然后将其作为对象的 key
,继续递归将后面的内容作为 value
,所以应该可以写出 TupleToNestedObject<R, U>
,答案2和答案3这里约束更全面一些,那为什么我们在传入泛型的时候进行了约束,条件判断的时候还需要约束一次呢?是因为当你定义一个泛型参数 T
并对其进行约束 T extends readonly PropertyKey[]
时,你是在告诉 TypeScript 编译器,任何使用 TupleToNestedObject
的地方,T
必须是一个只读的属性键数组。这个约束是在类型定义阶段就确定的,确保了 T
符合预期的类型结构。然后,在条件类型 T extends readonly [infer K extends PropertyKey, ...infer R extends readonly PropertyKey[]]
中,infer K extends PropertyKey
是在条件类型被检查时应用的。这个推断是在编译器检查类型时进行的,它确保了从 T
中推断出的第一个元素 K
是一个有效的属性键。
总结:
为什么需要两次约束?
- 泛型参数的约束:这是为了确保在使用
TupleToNestedObject
时,传入的类型T
符合预期的结构。它是一个类型级别的约束,确保了类型安全。 - 条件类型中的约束:这是为了确保在条件类型被展开时,能够正确地推断出类型。它是一个类型检查阶段的约束,确保了类型推断的正确性。