【问题标题】:Create key/value type from object type从对象类型创建键/值类型
【发布时间】:2021-11-26 13:38:08
【问题描述】:

假设我们有一个类型

type Foo = {
  a: string;
  b: number;
  c: boolean;
}

我现在想为具有给定类型Tkeyvalue 的对象定义一个类型,以便直接从键中推断出值的类型,这样我就可以做到:

const kv1: KeyValue<Foo> = {key: 'a', value: 'STRING'};
const kv2: KeyValue<Foo> = {key: 'b', value: 42};
const kv3: KeyValue<Foo> = {key: 'c', value: true};

如果我只是这样做:

type KeyValue<T> = {
  key: keyof T;
  value: T[keyof T]
}

...那么显然这些值将是Foo 中所有属性值的并集:

如果我这样做:

type KeyValue<T, K extends keyof T> = {
  key: K;
  value: T[K]
}

... 那么可以肯定,如果明确键入 KeyValue&lt;Foo, 'a'&gt; 我可以创建与 Foo:s 属性的类型匹配的对象文字,但如果我没有专门为每个文字提供类型和键但是只需执行KeyValue&lt;Foo, keyof Foo&gt;,每个值将被允许属于Foo 中的任何值的类型,即所有值都将是string | number | boolean,而不是从输入的key 推断出来。

最后我希望能够做这样的事情:

const kvs: Array<KeyValue<Foo>> = [
  {key: 'a', value: 'STRING'}, // should not compile if value is a number or boolean
  {key: 'b', value: 42}, // should not compile if value is a string or boolean
  {key: 'c', value: true}, // should not compile if value is a string or number
];

是否可以使用这些约束派生KeyValue 类型,从而在上面的第二个示例中有效地变为KeyValue&lt;Foo, 'a'&gt; | KeyValue&lt;Foo, 'b'&gt; | KeyValue&lt;Foo, 'c'&gt;,而无需手动编写此联合?基本上我想我想要的是能够从当前文字对象中key 的值推断value 的类型。

【问题讨论】:

    标签: typescript typescript-generics


    【解决方案1】:

    您不能使用单个 KeyValue 对象来表示每个键值对,因为这需要部分推断(对于键)或以某种方式从同一对象内的 value 属性中引用 key 属性。

    但是,您可以做的是使用输入对象创建一个可区分的联合。

    type Foo = {
      a: string;
      b: number;
      c: boolean;
    }
    
    type KeyValue<T> = {
      [P in keyof T]: {
        key: P;
        value: T[P];
      }
    }[keyof T];
    
    // with KeyValue<Foo>, this generates the following type
    // 
    // {
    //     key: "a";
    //     value: string;
    // } | {
    //     key: "b";
    //     value: number;
    // } | {
    //     key: "c";
    //     value: boolean;
    // }
    
    const kvs: Array<KeyValue<Foo>> = [
      {key: 'a', value: 40}, // ERROR
      {key: 'b', value: true}, // ERROR
      {key: 'c', value: "foo"}, // ERROR
    ];
    

    【讨论】:

    • 该死,现在那是聪明!赞一个!
    猜你喜欢
    • 2020-02-08
    • 2018-09-06
    • 2019-10-20
    • 1970-01-01
    • 2021-12-09
    • 2018-07-21
    • 2019-09-10
    • 2021-08-02
    相关资源
    最近更新 更多