首页 > 解决方案 > 打字稿键值关系保留 Object.entries 类型

问题描述

typescriptObject.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 的所有用例都不正确(请参阅此处),这对于我的具体情况来说没有问题。


尝试和失败的解决方案:

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<Obj, "a">["a", number],但是在第二行中将它keyof O作为第二个类型变量应用会再次导致与第一次尝试相同的结果。

标签: typescripttypescript-generics

解决方案


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


当您想将每个键与依赖于该键类型的内容配对时,请使用映射类型

type Entries<T> = {
    [K in keyof T]: [K, T[K]];
}[keyof T][];

type Test = Entries<Obj>;
// (["a", number] | ["b", string] | ["c", number])[]

第二个版本,它有一个包含属性的元组类型而不是一个联合,更难构造。可以将联合转换为元组,但您基本上不应该这样做。

第三个版本是可管理的,但比第一个版本复杂一点:你需要PickByValue这个答案

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])[]

游乐场链接


我想我还应该解释为什么 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<Obj>说这不可能发生,但实际上它可以发生;所以一般来说Entries<T>不是一个合理的返回类型Object.entriesObject.entries只有当您自己知道这些值没有多余的属性时,您才应该使用上述解决方案;Typescript 不会为你检查这个。


推荐阅读