You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript中表示任意对象的正确方式及keys函数选型探讨

四种泛型约束的差异分析及最优选择

你封装的keys函数核心是为了规避重复的类型断言,让Object.keys直接返回keyof O类型的数组。下面逐一分析你写的四种泛型约束的差异,并给出最优方案:

1. function keys<Key extends string | symbol | number, O extends Record<Key, unknown>>(object: O)

这种写法虽然可行,但存在冗余的泛型参数:Key会被自动推导为keyof O,额外声明它完全没必要。Record<Key, unknown>的作用是描述“键类型为Key、值类型为unknown的对象”,但O本身已经是具体的对象类型,这个约束并没有带来额外的类型安全性,反而增加了代码复杂度。

2. function keys<O extends Object>(object: O)

Object是TS中最宽泛的对象类型,它包含所有对象(普通对象、数组、函数、包装对象等),仅约束值不是原始类型。但它的语义偏向“具备所有对象通用方法的类型”(比如toString、valueOf),属于较旧的类型定义,TS官方现在更推荐使用语义更明确的object类型。

3. function keys<O extends {}>(object: O)

{}是空对象类型,语义上容易被误解为“只能传入无自身属性的对象”,但实际TS允许任何非原始值(包括带属性的对象)赋值给它。这种类型的语义和实际行为存在偏差,容易造成代码阅读者的误解,不推荐使用。

4. function keys<O extends object>(object: O)

object是TS2.2引入的类型,专门用来表示所有非原始值(普通对象、数组、函数、正则等),语义非常明确:“只接受非原始类型的值”。同时,泛型推导能完整保留O的具体属性信息,不会丢失类型细节,完全符合你封装函数的需求,是TS官方推荐的表示任意对象的类型。

最优方案

直接使用第四种写法即可:

function keys<O extends object>(object: O) {
  return Object.keys(object) as Array<keyof O>
}

补充说明:TS官方将Object.keys的返回值定义为string[],是因为JS中对象的键最终都会被转为字符串(Symbol键不会被Object.keys返回),且无法保证运行时对象的键和编译时keyof O完全一致(比如对象可能有额外的隐式属性)。但在你的业务场景中,如果你能确保对象的键与编译时类型完全匹配,使用as Array<keyof O>是安全且合理的类型断言。

内容的提问来源于stack exchange,提问作者opensas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 08:01:23