【问题标题】:Preserve key type when using Object.entries()使用 Object.entries() 时保留键类型
【发布时间】:2021-11-26 08:41:47
【问题描述】:

这是我的问题的一个示例 (demo in ts playground)

type Tkey = 'foo' | 'bar' | 'defaultKey'

const typedObject: Record<Tkey, Boolean> = {
  'foo': true,
  'bar': false,
  'defaultKey': true
}

// type does not persist string narrowing
const entries = Object.entries(typedObject) // [string, Boolean][]

所以[key, values] 中的key 是string 类型,而不是Tkey 类型。

作为一种解决方法,您可以事后手动强制,但最好在操作期间定义类型。

const typedEntries = entries as [Tkey, Boolean][]

【问题讨论】:

  • 这背后的原因是,与编译时相比,对象在运行时可能具有更多的属性。有关更多信息,请参阅 TypeScript PR#12253 上的 comment。实际上,您想要的行为之前在PR#12207 中合并,但后来在PR#12547 中删除。
  • 另请参阅question 了解更多上下文。

标签: typescript


【解决方案1】:

您可以通过添加您自己的对象定义来扩展default typescript lib,该对象定义接受两个泛型类型参数。

在您的项目根目录中添加以下globals.d.ts 文件:

interface ObjectConstructor {
    entries<TKey extends PropertyKey, TVal>(o: Record<TKey,TVal>): [TKey, TVal][];
    keys<TKey extends PropertyKey>(obj: Record<TKey,any>): TKey[];
}

然后像这样使用它:

const entries = Object.entries<ObjKeys, Boolean>(myObj) // [ObjKeys, Boolean][]
const keys = Object.keys<ObjKeys>(myObj) // ObjKeys[]

Demo in TS Playground

【讨论】:

  • 感谢您的赏金?虽然我不值得您的回答比我的更准确!
【解决方案2】:

TypeScript 的原生定义文件包含 Object.entries:

entries<T>(o: { [s: string]: T } | ArrayLike<T>): [string, T][];

entries(o: {}): [string, any][];

您获得所需行为的唯一机会是使用以下内容覆盖此定义:

interface YourOwnObject {
  entries<T>(o: { [K in keyof T]: T[K] }): [keyof T, T[keyof T]][];
}

(<YourOwnObject>Object).entries(typedObject).forEach(([key, values]) => {
  // ...
})

【讨论】:

  • 有没有办法在全球范围内做到这一点?你能想象为什么这没有写入原生定义吗??
  • 我已经用一种可能的方式进行了编辑。不幸的是,您无法修改现有的ObjectInterface,我不知道为什么不将其写入本机定义文件。
  • 你有本地打字稿源代码的链接吗?
  • 你甚至不需要想象为什么这不是写在原生定义中。有书面记录说明为什么没有将其写入原生定义? 请参阅我的comment 原帖。
猜你喜欢
  • 2020-09-15
  • 2023-01-10
  • 2020-05-25
  • 1970-01-01
  • 2021-11-20
  • 2020-06-15
  • 2020-11-18
  • 1970-01-01
  • 2022-07-21
相关资源
最近更新 更多