Object.keys 的原生 JS 类型之困

前言

TS 项目开发时,大家想必都遭遇过一个颇为头疼的状况:原生 JS 的一些方法,类型定义并不完善。日常编码中,这就像个小 "绊脚石",你本想高效推进项目,却常常因为它,不得不暂停下来,写一堆额外代码去弥补类型缺失带来的隐患,无端耗费许多精力,别提多闹心了。

被被这问题纠缠久了,我实在忍无可忍。与其每次都临时抱佛脚应付,不如主动出击,彻查根源,找个能彻底改善局面的法子。

下面,我打算以 Object.keys 为典型案例,进行深入剖析,旨在为面临同样困境的开发者提供有益的参考与启发。

问题描述

深入探究 Object.keys 原始的类型定义,可归纳出两个关键特征:

通过上面代码我们可以看到两个点

  1. 该方法隶属于 ObjectConstructor 范畴。
  2. 其参数类型仅被简单定义为 object,返回值类型为 string[],且不支持泛型这一特性,致使其类型表达能力受限。

如此的类型设定,在实际编码中极易引发问题。参考以下示例代码

typescript 复制代码
const obj = { aaa: "0001", bbb: "0002" };

Object.keys(obj).forEach((key) => {
  obj[key] // 类型报错
  ~~~~~~~~
  // 元素隐式具有 "any" 类型,因为类型为 "string" 的表达式不能用于索引类型 "{ aaa: string; bbb: string; }"。
  // 在类型 "{ aaa: string; bbb: string; }" 上找不到具有类型为 "string" 的参数的索引签名。
});

由上述代码可见,当使用 Object.keys 提取对象的可枚举属性名,并尝试基于这些属性名迭代获取对应属性值时,类型错误便随之产生。

面对此类问题,部分开发者可能会采取临时的类型断言措施,如 (Object.keys(obj) as (keyof typeof obj)[]).forEach...。然而,这种方式仅能解一时之急,无法满足代码准确性与简洁性的长远需求。开发者真正期望的是,Object.keys 能够智能、精准地依据对象实例推导其包含的属性信息,而非仅仅返回一个宽泛的 string[]

基于对该问题的深度困扰,探索如何重塑 Object.keys 的类型,以实现精准的类型推导,成为解决问题的关键思路。经研究发现,利用全局类型声明文件覆盖原有的类型定义,是一条可行的解决路径。

解决方案

  1. 首先,创建一个以 .d.ts 结尾的文件,此类文件作为类型声明文件,在 TS 项目的类型管理体系中发挥着关键作用。
  2. 鉴于前文对 Object.keys 所属范畴的分析,需在类型声明文件中对 ObjectConstructor 进行针对性处理。具体操作如下:
typescript 复制代码
// window.d.ts

interface ObjectConstructor {
  keys<T>(o: T): (keyof T)[]; // 覆盖 Object.keys 的类型
}

值得一提的是,通过 interface 在类型声明文件中声明的类型,具备全局可用性,能够在整个项目代码范围内有效约束类型,保障代码的类型安全性。

经上述改造后,再次使用 Object.keys 时,令人欣喜的是,其已能够自动推导出精准的返回值类型,如 ("aaa" | "bbb")[],达成了预期的优化效果。

相关推荐
拉不动的猪2 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪2 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
uhakadotcom3 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom3 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom3 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试
uhakadotcom4 小时前
Node.js 包管理器:npm vs pnpm
前端·javascript·面试
咖啡教室5 小时前
前端开发日常工作每日记录笔记(2019至2024合集)
前端·javascript
咖啡教室5 小时前
前端开发中JavaScript、HTML、CSS常见避坑问题
前端·javascript·css
市民中心的蟋蟀8 小时前
第五章 使用Context和订阅来共享组件状态
前端·javascript·react.js
逆袭的小黄鸭8 小时前
JavaScript 闭包:强大特性背后的概念、应用与内存考量
前端·javascript·面试