typescript 如何获取作为对象嵌套值的所有基元类型的联合类型?

cgyqldqp  于 2023-05-08  发布在  TypeScript
关注(0)|答案(2)|浏览(219)

我需要在一个对象内部使用所有的基本类型(加上null)。
到目前为止,我发现的所有答案都只适用于简单的对象。但是我的那些是深度嵌套的,并且有包含对象的数组。
例如,对于这个对象:

const Data = {
  a: {
    x: "foo",
  },
  b: {
    x: [123, 45],
    y: [
      {
        x: null,
      },
      { x: Symbol(666) },
    ],
  },
};

我尝试派生类型(字符串|号码|零|符号)

type foo = DERIVE<typeof Data>    // foo = string | number | null | symbol

到目前为止,我在SO上找到的东西让我走了这么远(这完全是一团糟,对不起):

type RecursiveValues<T> = {
  [Prop in keyof T]:
  (T[Prop] extends Array<any> ? RecursiveValues<T[Prop][number]> : T[Prop] extends object
    ? RecursiveValues<T[Prop]>
    : T[Prop])
}[keyof T]
type TestValues = RecursiveValues<typeof Data>
pn9klfpd

pn9klfpd1#

这件事有两个难点。
1.该类型需要递归才能钻取到所有叶子
1.数组需要特殊处理,因为keyof unknown[]将包含数组所具有的方法。
你想要这样的东西:

type Primitive = string | number | boolean | symbol | null | undefined | ((...args: any[]) => any)

type DERIVE<T> =
  T extends Primitive ? T
  : T extends readonly unknown[] ? DERIVE<T[number]>
  : DERIVE<T[keyof T]>

这里Primitive类型的存在是为了知道何时停止钻取。如果遇到这些类型,则递归停止。您将需要使用希望以其结束的值来自定义此列表。
现在我们可以转到DERIVE类型本身。让我们一行一行地走:

  • T extends Primitive ? T如果类型是基元,则返回它。否则继续。
  • : T extends readonly unknown[] ? DERIVE<T[number]>如果类型是数组,则派生其成员的类型。否则继续。
  • : DERIVE<T[keyof T]>其他检查失败,因此我们假设这是一个对象类型,并派生T的每个属性类型。

现在,这将按照您的预期工作:

type Foo = DERIVE<typeof Data> // string | number | null | symbol

见操场

lf5gs5x2

lf5gs5x22#

type primitive = string | number | boolean | symbol | null | undefined | bigint | Function
type DERIVE<T> = 
  | T extends primitive ? T
  : DERIVE<T extends ReadonlyArray<any> ? T[number] : T[keyof T]>

请注意,如果希望值为文字,则可能需要定义对象as const

相关问题