es-toolkit 兼容层 `isSafeInteger` 详解:安全整数判定、类型收窄与原生替代方案
2026/9/15 14:29:36 网站建设 项目流程

es-toolkit 兼容层isSafeInteger详解:安全整数判定、类型收窄与原生替代方案

【免费下载链接】es-toolkitA modern JavaScript utility library that's 2-3 times faster and up to 97% smaller, a major upgrade to lodash.项目地址: https://gitcode.com/GitHub_Trending/es/es-toolkit

isSafeInteger是 es-toolkit 为兼容 lodash 而提供的谓词函数,用于判断一个值是否为"安全整数"(safe integer),即能被 IEEE 754 双精度浮点数精确表示的整数。本文以 isSafeInteger 兼容层文档 为主体,结合 源码实现 与 单元测试,完整讲解它的判定规则、类型收窄能力、与isInteger/isNumber的区别,以及官方给出的原生替代建议。读完你将能在数值校验、边界防御和 TypeScript 类型收窄场景中正确选用该 API。

什么是"安全整数"

JavaScript 的number采用 IEEE 754 双精度浮点数格式,只能精确表示-(2^53 - 1)2^53 - 1之间的整数,即-90071992547409919007199254740991。超出该范围时,相邻整数可能被舍入到同一个值,导致精度丢失。

在 实现源码 的注释中对此有明确说明:安全整数是可以作为number精确表示、且不会有其他整数被舍入到它的整数。判定范围包括两个端点(闭区间)。

快速上手

从 compat 入口导入并调用:

import { isSafeInteger } from 'es-toolkit/compat'; // 安全整数 isSafeInteger(3); // true isSafeInteger(-42); // true isSafeInteger(0); // true isSafeInteger(Number.MAX_SAFE_INTEGER); // true (9007199254740991) isSafeInteger(Number.MIN_SAFE_INTEGER); // true (-9007199254740991) // 超出安全范围的整数 isSafeInteger(Number.MAX_SAFE_INTEGER + 1); // false isSafeInteger(Number.MIN_SAFE_INTEGER - 1); // false isSafeInteger(9007199254740992); // false // 非整数的数值 isSafeInteger(3.14); // false isSafeInteger(Infinity); // false isSafeInteger(-Infinity); // false isSafeInteger(NaN); // false // 非 number 类型 isSafeInteger('3'); // false isSafeInteger(1n); // false (BigInt) isSafeInteger([]); // false isSafeInteger({}); // false isSafeInteger(null); // false isSafeInteger(undefined); // false

参数与返回值

  • valueunknown):待检查的值。
  • 返回value is number:当值为安全整数时返回true,否则返回false

值得注意的是,虽然签名接受任意类型,但任何非number类型(包括BigInt、字符串、对象、nullundefined)都会直接返回false,不会发生隐式转换。

从源码看实现本质

整个实现只有一行:

// src/compat/predicate/isSafeInteger.ts export function isSafeInteger(value: unknown): value is number { return Number.isSafeInteger(value); }

它直接委托给原生Number.isSafeInteger。这也解释了两个关键特性:

  1. 零转换语义Number.isSafeInteger会先检查类型是否为number,因此1n'3'[]等都不会被"矫正"成数字后再判断。
  2. 类型收窄:返回类型声明为value is number,是标准的 TypeScript 类型谓词(type predicate)。

在 src/compat/compat.ts#L234 和 src/browser.ts#L232 中均通过export { isSafeInteger }对外公开,分别支持es-toolkit/compat与浏览器构建两种入口。

TypeScript 类型收窄示例

const value: unknown = 3; if (isSafeInteger(value)) { // 此处 value 已被收窄为 number console.log(value.toFixed(2)); // 类型安全地调用 number 方法 }

单元测试 中通过expectTypeOf(value).toEqualTypeOf<number>()验证了这种收窄行为。

测试用例验证的判定边界

isSafeInteger.spec.ts 覆盖了完整的边界场景:

输入期望结果依据
-101true整数均为安全整数(spec#L60-L67)
1.13.14false浮点数不是整数(spec#L17-L20)
1nfalseBigInt 不参与判定(spec#L22-L25)
NaNInfinity-Infinityfalse非有限数值(spec#L37-L45)
Number.MAX_SAFE_INTEGER + 2false超出上限(spec#L52-L55)
Number.MIN_SAFE_INTEGER - 2false低于下限(spec#L47-L50)
Object(1)truenew Date()/x/symbolfalseyfalse非 number 或包装对象(spec#L70-L95)

测试还特别验证了1.7976931348623157e308(接近Number.MAX_VALUE)会返回false,因为它远超安全整数上限。

isIntegerisNumber的区分

compat 层还提供了两个易混淆的兄弟函数,它们的判定粒度不同:

  • isInteger:仅判断是否为整数,不限制范围。Number.MAX_SAFE_INTEGER + 1会被判为true。实现见 isInteger.ts,直接委托Number.isInteger
  • isNumber:只要值是number类型(含NaNInfinity)就返回true,甚至识别new Number(42)包装对象。实现见 isNumber.ts,通过typeofgetTag双重判断。
  • isSafeInteger:三者中最严格,要求"是整数 + 在安全范围内 + 原始 number 类型"。

典型选用规则:需要"任意整数"用isInteger;需要"是数字(含非有限值)"用isNumber;需要"可安全参与整数运算"用isSafeInteger

在仓库其他模块中的实际应用

Number.isSafeInteger的语义在 es-toolkit 内部也被复用:

  • isLength.ts 用Number.isSafeInteger(value) && value >= 0判断合法的数组长度,因为数组length必须是安全范围内的非负整数。
  • times.ts 用!Number.isSafeInteger(n)提前拒绝超范围的调用次数,避免危险循环。

这说明"安全整数"判定是数值校验体系的基础构件,常用于数组长度、循环次数、索引运算等对精度敏感的防御性检查。

官方建议:优先使用原生Number.isSafeInteger

原文档开篇即给出醒目警告(isSafeInteger.md):

由于额外的类型检查开销,这个isSafeInteger函数运行较慢。请改用更快、更现代的Number.isSafeInteger

原因在于 compat 层为了保持与 lodash 的 API 签名(接受any并保持宽松调用方式)而引入的函数包装开销。从 实现源码 可见,最终行为与原生 API 完全一致,因此在新代码中直接使用Number.isSafeInteger(value)即可获得完全相同的判定结果与更高的性能。

只有在以下场景才推荐使用 compat 版本:

  • 需要与 lodash 风格的既有代码保持一致,便于迁移;
  • 需要value is number这一类型谓词带来的类型收窄体验(原生Number.isSafeInteger不提供类型收窄);
  • 在统一封装层中希望通过es-toolkit/compat单一入口管理所有谓词函数。

总结

  • isSafeInteger判定-(2^53 - 1)2^53 - 1)闭区间内的整数,超出即返回false
  • 底层直接委托Number.isSafeInteger,行为一致、无隐式类型转换。
  • 返回类型谓词value is number,可在if分支中安全收窄类型。
  • isInteger(不限范围)、isNumber(含非有限值与包装对象)形成三级严格度差异。
  • 对性能敏感的新代码,官方建议直接用原生Number.isSafeInteger

【免费下载链接】es-toolkitA modern JavaScript utility library that's 2-3 times faster and up to 97% smaller, a major upgrade to lodash.项目地址: https://gitcode.com/GitHub_Trending/es/es-toolkit

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询