【问题标题】:Typescript Key-Value relation preserving Object.entries type打字稿键值关系保留 Object.entries 类型
【发布时间】:2020-05-25 06:33:24
【问题描述】:

typescript 提供的Object.entries 的键入具有返回类型[string, T][],但我正在寻找一个泛型类型Entries<O> 来表示此函数的返回值,该函数保持键和值之间的关系。

例如。当有像

这样的对象类型时
type Obj = {
    a: number,
    b: string,
    c: number
}

我正在寻找一种Entries<O> 类型,当提供Obj 时会产生以下类型之一(或类似的类型):

(["a", number] | ["b", string] | ["c", number])[]
[["a", number], ["b", string], ["c", number]]
(["a" | "c", number] | ["b", string])[]

这对于 Object.entries (see here) 的所有用例并不正确,这对我的具体情况来说没有问题。


尝试失败的解决方案:

type Entries<O> = [keyof O, O[keyof O]][] 对此不起作用,因为它只保留可能的键和值,但不保留它们之间的关系,因为 Entries<Obj>["a" | "b" | "c", number | string]

type Entry<O, K extends keyof O> = [K, O[K]]
type Entries<O> = Entry<O, keyof O>[]

这里Entry 的定义按预期工作,例如。 Entry&lt;Obj, "a"&gt;["a", number],但在第二行中使用 keyof O 作为第二个类型变量会再次导致与第一次尝试相同的结果。

【问题讨论】:

    标签: typescript typescript-generics


    【解决方案1】:

    这是一个解决方案,但是当使用它作为Object.entries 的返回类型时小心;这样做并不总是安全的(见下文)。


    如果您想将每个密钥与依赖于该密钥类型的内容配对,请使用mapped type

    type Entries<T> = {
        [K in keyof T]: [K, T[K]];
    }[keyof T][];
    
    type Test = Entries<Obj>;
    // (["a", number] | ["b", string] | ["c", number])[]
    

    第二个版本,它有一个包含属性的元组类型而不是一个联合,更难构造; it is possible to convert a union to a tuple 但你基本上不应该这样做。

    第三个版本是可管理的,但比第一个版本复杂一点:你需要 PickByValue from this answer

    type Entries3<T> = {
        [K in keyof T]: [keyof PickByValue<T, T[K]>, T[K]]
    }[keyof T][];
    
    type Test3 = Entries3<Obj>;
    // (["a" | "c", number] | ["b", string])[]
    

    Playground Link


    我想我也应该解释一下为什么 Typescript Object.entries 提供更强的类型。当你有一个像type Obj = {a: number, b: string, c: number} 这样的类型时,它只保证一个值具有这些属性; 保证该值不具有其他属性。例如,值 {a: 1, b: 'foo', c: 2, d: false} 可分配给类型 Obj(除了对象文字的额外属性检查)。

    在这种情况下,Object.entries 将返回一个包含元素 ['d', false] 的数组。 Entries&lt;Obj&gt; 类型表示这不可能发生,但实际上它可以发生;所以Entries&lt;T&gt; 通常不是Object.entries 的合理返回类型。当您自己知道这些值没有多余的属性时,您应该只使用上述解决方案和Object.entries; Typescript 不会为你检查这个。

    【讨论】:

      【解决方案2】:

      我们可以做如下的专用函数:

      depictObjectKeyType<O>(o: O) {
          return Object.keys(o) as (keyof O)[];
      }
      
      depictEntriesKeyType<T>(obj: T): Entries<T> {
          return Object.entries(obj) as any;
      }
      

      并用作:

      this.depictEntriesKeyType(data).forEach(....
      

      【讨论】:

        猜你喜欢
        • 2023-01-10
        • 1970-01-01
        • 2020-09-15
        • 2020-03-09
        • 2021-10-25
        • 1970-01-01
        • 2012-10-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多