首页 > 解决方案 > 如何在元组类型中表示所有可能的对象路径

问题描述

给定一个 object type SomeRecord = {a: {a1: 'a1', a2: 'a2'}, b: {b1: 'b1'}},我想要一个Path<T extends Record<string, any>>将所有可能的记录路径表示为元组的类型:

// Path<SomeRecord> will be a union of:
['a']
['a', 'a1']
['a', 'a2']
['b']
['b', 'b1']
// And nothing else

我阅读了大量关于路径是函数参数的建议。这对我不起作用,因为我只需要元组。

标签: typescripttypescript-generics

解决方案


在我们开始之前,并不是说生成所有可能路径的联合可能很昂贵。在编译时间方面。此外,以下解决方案使用递归条件类型,它们有自己的性能问题,不鼓励使用。

最优雅的解决方案是使用 4.0(尚未发布)中的新 TS 功能,该功能允许在其他元组中传播元组,如此所述。有了这个和递归条件类型,我们可以创建所有可能的元组路径:

type SomeRecord = { a: { a1: 'a1', a2: 'a2' }, b: { b1: 'b1', b2: { b21: string, b22: string, } } }


type Paths<T, K extends keyof T = keyof T> = K extends K ? [K, ...{
    0: []
    1: [] | Paths<T[K]>    
}[T[K] extends string | number | boolean ? 0: 1]] : never;

type x = Paths<SomeRecord>

游乐场链接

它的工作方式是,我们获取 中的每个键T,并使用分布式条件类型来获取每个键K并创建一个元组,其中K是第一项,然后是:

  • []如果T[K]没有我们感兴趣的其他键(即原语),则空元组 ( ) o
  • 或由[](为了允许只是[K])与 . 类型的路径联合组成的元组T[K]

未标准化的结果将类似于['a', ...([] | ['a1'] | ['a2'])] | ['b', ...([] | ['b1'] | ['b2', ...([] | ['b21'] | ['b22'] ])]. 幸运的是,编译器会将这种怪物标准化为["a"] | ["a", "a1"] | ["a", "a2"] | ["b"] | ["b", "b1"] | ["b", "b2"] | ["b", "b2", "b21"] | ["b", "b2", "b22"]


推荐阅读