Object.keys不遵循字典键类型,TypeScript中如何实现预期行为?
关于Object.keys()在数字索引对象下的类型问题
为什么Object.keys()返回字符串数组?
JavaScript中对象的键本质上只能是字符串或Symbol类型——哪怕你用数字作为键赋值,JS引擎也会自动把它转成字符串存储。TypeScript的类型定义严格贴合JS的运行时行为,所以lib.es5.d.ts里Object.keys()的返回类型被定义为string[],而非泛型。
TS风格的解决方式
如果你确定对象的键确实都是数字类型,可以通过以下方式实现预期的类型提示:
- 类型断言:直接将结果断言为数字数组,注意需要自己保证运行时的类型安全(比如对象没有被额外添加字符串键):
const obj: { [key: number]: string } = { 1: "a", 2: "b" }; const keys = Object.keys(obj) as unknown as number[]; - 自定义工具函数:封装一个类型约束更严格的函数,利用
keyof T来推导数字键类型:function getNumberKeys<T extends { [key: number]: unknown }>(obj: T): (keyof T)[] { return Object.keys(obj) as (keyof T)[]; } // 使用示例 const obj: { [key: number]: string } = { 1: "a", 2: "b" }; const keys = getNumberKeys(obj); // keys类型为number[]
官方未将Object.keys()设为泛型的原因
TypeScript的核心原则是不违背JavaScript的运行时行为。如果把Object.keys()定义为泛型并返回keyof T类型,会存在类型安全隐患:比如你在TS里定义了数字索引对象,但运行时可能有人给对象添加了字符串键,此时泛型返回的类型就和实际运行结果不符,反而会误导开发者。官方选择保守的string[]作为返回类型,是为了让开发者明确知晓JS的实际行为。
新版本是否解决了该问题?
截至2024年,TypeScript官方仍未修改Object.keys()的返回类型定义。因为上述的类型安全矛盾是JS底层逻辑决定的,只要JS对象的键处理规则不变,TS就不会调整这个类型定义。
内容的提问来源于stack exchange,提问作者G. B. Wanscher
相关产品推荐
相关产品推荐

