【问题标题】:Create a union from values of a nested object with different keys从具有不同键的嵌套对象的值创建联合
【发布时间】:2020-07-31 12:15:17
【问题描述】:

鉴于我有以下Options 类型

interface Options {
  parent1: {
    child1: {
      foo: 'bar'
    }
  };
  parent2: {
    child2: {
      baz: 'daz'
    }
  };
}

在这种情况下,如何将其变成所有 2 级子属性值的并集

{ foo: 'bar' } | { baz: 'daz' }

我尝试了以下

type KnownOptions = Options[keyof Options][keyof Options[keyof Options]];

但这只有在所有顶级属性中的第 2 级子属性都相同时才有效。例如。当我将child2 重命名为 `child1

Playground

【问题讨论】:

    标签: typescript


    【解决方案1】:

    您可以使用映射类型来获取嵌套类型:

    type KnownOptions<T> = T extends {
      [k in keyof T]: {
        [k: string]: infer OptionValue
      }
    } ? OptionValue : never
    
    // Good:
    const a: KnownOptions<Options> = { foo: 'bar' }
    const b: KnownOptions<Options> = { baz: 'daz' }
    
    // Expect errors:
    const c: KnownOptions<Options> = { foo: 'bad value' }
    const d: KnownOptions<Options> = { badKey: 'bar' }
    

    Playground

    这是一个泛型类型,它接受具有两级键的类型。条件类型(由三元 T extends Type ? A : B 指出)表示“如果泛型类型 T 是至少 2 级深度的对象,则返回每个第二级的类型。否则,返回 never 类型,因为泛型类型无效。

    infer OptionalValue 表示“无论是什么类型,都保存为OptionValue”。然后由条件类型返回,在将多个类型保存到它之后,创建每个类型的联合。

    我必须承认,我不完全确定为什么第一级密钥需要是 k in keyof T 而第二级可能只是 k: string。但是,这是我让它正常工作的唯一方法。

    【讨论】:

      【解决方案2】:

      我会这样写KnownOptions

      type KnownOptions = { [K in keyof Options]: Options[K][keyof Options[K]] }[keyof Options];
      

      这里我们将mapping Options 的每个属性都连接到 its 属性的联合中,然后将所有这些联合联合在一起。如果我们按照这样定义的ValueOf&lt;T&gt; 编写它可能更有意义:

      type ValueOf<T> = T[keyof T];
      
      type KO = ValueOf<{ [K in keyof Options]: ValueOf<Options[K]> }>;
      

      所以ValueOf&lt;T&gt; 为您提供对象T 的属性值类型的联合(例如,ValueOf&lt;{a: string, b: number}&gt;string | number),所以您正在做的是将Options 的每个属性映射到@ 987654334@ 然后把ValueOf 全部拿走。

      您可以根据需要验证每个定义的计算结果为 {foo: "bar";} | {baz: "daz";}


      好的,希望对您有所帮助;祝你好运!

      Playground link to code

      【讨论】:

        【解决方案3】:

        您可以使用['propName'] 表示法对类型进行索引以提取类型

        type KnownOptions = Options['parent1']['child1'] | Options['parent2']['child2']

        【讨论】:

          猜你喜欢
          • 2020-07-17
          • 2022-01-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-09-16
          • 2018-07-24
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多