【问题标题】:Is it possible to get the keys from a union of objects?是否可以从对象的联合中获取密钥?
【发布时间】:2020-08-24 08:46:05
【问题描述】:

最简单的例子

假设这种类型

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

有没有可能获得

type KeysOfFoo = 'a' | 'b' | 'c';

我试过了,但是不行

type Failed = keyof Foo; // never

TsPlayground

【问题讨论】:

    标签: typescript typescript3.0


    【解决方案1】:

    Failednever 类型,因为您的 Foo 类型不能有任何键。它目前设置为 3 种完全互斥类型之间的交集类型,因此没有有效的键。

    如果您从使用 | 更改为 &,那么它将照常工作。

    type Foo = { a: number } & { b: string } & { c: boolean }
    
    type a = keyof Foo // 'a' | 'b' | 'c'
    

    Playground Link

    【讨论】:

    • 请注意| 是一个并集,而不是一个交集。并且这三种类型不是独有的;他们只是不共享任何声明的属性。 {a: number}{a: string} 将是独占的,因为您无法拥有同时满足这两种类型的对象。
    【解决方案2】:

    keyof (A | B | C) 这样的东西只会导致A | B | C 类型的对象上绝对 的键,这意味着它必须是已知在all 的 ABC,即:keyof A & keyof B & keyof C。也就是说,keyof T 是“contravariant in T”。 不过,这不是您想要的(在您的情况下,没有共同的键,所以交叉点是 never)。

    如果您正在寻找您的工会成员中至少一个 中的一组键,您需要分发 keyof 运算符工会成员。幸运的是,有一种方法可以通过distributive conditional types 做到这一点。它看起来像这样:

    type AllKeys<T> = T extends any ? keyof T : never;
    

    T extends any 在类型检查方面并没有做太多的事情,但它确实向编译器发出信号:T 上的操作应该分别针对T 的每个联合成员进行,然后结果将合并回来一起成为一个工会。这意味着AllKeys&lt;A | B | C&gt; 将被视为AllKeys&lt;A&gt; | AllKeys&lt;B&gt; | AllKeys&lt;C&gt;。让我们试试吧:

    type KeysOfFoo = AllKeys<Foo>;
    // type KeysOfFoo = "a" | "b" | "c"
    

    看起来不错!请注意,在实际使用KeysOfFooFoo 类型的对象时应小心。 keyof 逆变是有原因的:

    function hmm(foo: Foo, k: AllKeys<Foo>) {
      foo[k]; // error!
      // "a" | "b" | "c"' can't be used to index type 'Foo'.
      // Property 'a' does not exist on type 'Foo'
    }
    

    使用kfoo 进行索引是不安全的,原因与您不能使用"b" 安全地对{a: number} 类型的值进行索引的原因相同...对象上可能不存在该键。显然你比我更了解你的用例,所以你很可能一起合法地使用AllKeys&lt;Foo&gt;Foo。我只是说要小心。


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

    Playground link to code

    【讨论】:

    • 谢谢~!不敢相信就这么简单
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-08-18
    • 2019-07-19
    • 2020-08-08
    • 1970-01-01
    • 2019-06-08
    • 2012-10-09
    • 1970-01-01
    相关资源
    最近更新 更多