typeinfo
typeinfo 是一个轻量级的JavaScript库,它扩展了typeof
操作符的功能,允许获取
JavaScript 变量更精确可靠的类型信息。它为最新的 ECMAScript 标准提供了增强支持,并为您的项目
中的类型识别提供了全面的解决方案。
JavaScript的原生typeof
操作符在检测复杂对象类型时有很多局限性。本库通过提供详细的类型信息来解决这些局限性,帮助开发者构建具有正确类型处理的更健壮的应用程序。
目录
特性
- 提供比
typeof
更准确的JavaScript变量类型信息 - 全面检测JavaScript内置类型(支持100多种类型)
- 支持最新的ECMAScript标准,包括ES6+特性
- 兼容浏览器和Node.js环境
- 零依赖,轻量级(压缩后<4KB)
- 100%测试覆盖率
- 详细的类型分类,使类型检查更容易
- 为不同环境下的高级类型处理提供特性检测
- 易于集成到现有项目中
- 支持用户自定义类的类型信息
- 支持跨域(不同JavaScript上下文)创建的对象的类型检测
安装
您可以通过 npm
安装 typeinfo:
npm install @qubit-ltd/typeinfo
或者通过 yarn
安装:
yarn add @qubit-ltd/typeinfo
示例
下面是实现深度克隆函数的使用示例:
import typeInfo from '@qubit-ltd/typeinfo';
function clone(value) {
const info = typeInfo(value);
switch (info.type) {
case 'undefined': // drop down
case 'null': // drop down
case 'boolean': // drop down
case 'number': // drop down
case 'string': // drop down
case 'symbol': // drop down
case 'bigint': // drop down
case 'function': // drop down
return value; // don't need to clone immutable objects
case 'object': // drop down
default:
switch (info.subtype) {
case 'Boolean': // drop down
case 'Number': // drop down
case 'String': // drop down
return value; // don't need to clone immutable objects
case 'Date':
return new Date(value);
case 'RegExp':
return new RegExp(value);
// ...处理其他对象类型
}
}
}
或者使用 info.category 简化代码逻辑:
import typeInfo from '@qubit-ltd/typeinfo';
function clone(value) {
const info = typeInfo(value);
switch (info.category) {
case 'undefined': // drop down
case 'null': // drop down
case 'primitive': // drop down
case 'function':
return value; // don't need to clone immutable objects
case 'primitive-wrapper':
return value; // don't need to clone immutable objects
case 'date':
return new Date(value);
case 'regexp':
return new RegExp(value);
case 'array':
return Array.from(value).map(item => clone(item));
case 'map':
const newMap = new Map();
value.forEach((val, key) => newMap.set(clone(key), clone(val)));
return newMap;
// ...处理其他类别
}
}
另一个展示DOM对象类型检测的示例:
import typeInfo from '@qubit-ltd/typeinfo';
function isElement(value) {
const info = typeInfo(value);
return info.category === 'DOM' && info.subtype === 'Element';
}
// 检查值是否为DOM节点
function isDomNode(value) {
const info = typeInfo(value);
return info.category === 'DOM';
}
使用
该库提供以下函数:
function typeInfo(value)
- 参数:
value: any
:指定的值。
- 返回值:
object
:关于指定值类型的信息。
这个函数返回关于指定值的精确类型信息。返回的信息是一个具有以下属性的对象:
type: string
: 指定值的类型名称。这与内置的typeof
操作符返回的值相同,不同的是null
值的类型是'null'
而不是'object'
,并且我们增加了'global'
表示 global object 的类型。subtype: string
: 指定值的子类型名称。此属性仅在指定值的类型为'object'
或'function'
时存在。category: string
:指定值的类别。这个属性适用于所有类型的值。更多详情请见Category。isPrimitive: boolean
: 是否为原始值。isBuiltIn: boolean
: 是否为JavaScript内置的原始值或内置对象。constructor: function
: 指定值的构造函数。此属性仅在指定值的类型为'object'
时存在。
Type
由 typeInfo()
返回的类型信息对象具有一个 type
属性,它可能具有以下值:
'undefined'
: 如果值为undefined
。'null'
: 如果值为null
。'boolean'
: 如果值为原始布尔值。'number'
: 如果值为原始数值。'string'
: 如果值为原始字符串值。'symbol'
: 如果值为符号值。'bigint'
: 如果值为原始bigint值。'function'
: 如果值为函数。'object'
: 如果值为普通对象。
type
属性的值类似于内置的 typeof
操作符返回的值,不同之处在于 null
的类型是 'null'
而不是 'object'
。
Subtype
如果值的类型为function
或object
,typeInfo()
返回的类型信息对象将包含subtype
属性,
它是指定值的详细子类型名称。
'function'
类型的可能subtype
名称包括:
'Function'
: 如果值为同步函数。'GeneratorFunction'
: 如果值为同步生成器函数。'AsyncFunction'
: 如果值为异步函数。'AsyncGeneratorFunction'
: 如果值为异步生成器函数。
请注意,'AsyncFunction'
和'AsyncGeneratorFunction'
子类型只在支持异步函数的
JavaScript 引擎中可用。
'object'
类型的可能subtype
名称包括:
'Boolean'
: 如果值为JavaScript内置的Boolean
对象。'Number'
: 如果值为JavaScript内置的Number
对象。'String'
: 如果值为JavaScript内置的String
对象。'RegExp'
: 如果值为正则表达式,即JavaScript内置的RegExp
对象。'Date'
: 如果值为JavaScript内置的Date
对象。'Map'
: 如果值为JavaScript内置的Map
对象。'WeakMap'
: 如果值为JavaScript内置的WeakMap
对象。'Set'
: 如果值为JavaScript内置的Set
对象。'WeakSet'
: 如果值为JavaScript内置的WeakSet
对象。'Array'
: 如果值为JavaScript内置的Array
对象。'Int8Array'
: 如果值为JavaScript内置的Int8Array
对象。'Uint8Array'
: 如果值为JavaScript内置的Uint8Array
对象。'Uint8ClampedArray'
: 如果值为JavaScript内置的Uint8ClampedArray
对象。'Int16Array'
: 如果值为JavaScript内置的Int16Array
对象。'Uint16Array'
: 如果值为JavaScript内置的Uint16Array
对象。'Int32Array'
: 如果值为JavaScript内置的Int32Array
对象。'Uint32Array'
: 如果值为JavaScript内置的Uint32Array
对象。'BigInt64Array'
: 如果值为JavaScript内置的BigInt64Array
对象。'BigUint64Array'
: 如果值为JavaScript内置的BigUint64Array
对象。'Float32Array'
: 如果值为JavaScript内置的Float32Array
对象。'Float64Array'
: 如果值为JavaScript内置的Float64Array
对象。'ArrayBuffer'
: 如果值为JavaScript内置的ArrayBuffer
对象。'SharedArrayBuffer'
: 如果值为JavaScript内置的SharedArrayBuffer
对象。'DataView'
: 如果值为JavaScript内置的DataView
对象。'WeakRef'
: 如果值为JavaScript内置的WeakRef
对象。'Promise'
: 如果值为JavaScript内置的Promise
对象。'Error'
:如果值为JavaScript内置Error
类的对象。'EvalError'
:如果值为JavaScript内置EvalError
类的对象。'RangeError'
:如果值为JavaScript内置RangeError
类的对象。'ReferenceError'
:如果值为JavaScript内置ReferenceError
类的对象。'SyntaxError'
:如果值为JavaScript内置SyntaxError
类的对象。'TypeError'
:如果值为JavaScript内置TypeError
类的对象。'URIError'
:如果值为JavaScript内置URIError
类的对象。'AggregateError'
:如果值为JavaScript内置AggregateError
类的对象。'InternalError'
:如果值为JavaScript内置InternalError
类的对象。'Intl.Collator'
: 如果值为JavaScript内置的Intl.Collator
对象。'Intl.DateTimeFormat'
: 如果值为JavaScript内置的Intl.DateTimeFormat
对象。'Intl.DisplayNames'
: 如果值为JavaScript内置的Intl.DisplayNames
对象。'Intl.DurationFormat'
: 如果值为JavaScript内置的Intl.DurationFormat
对象。'Intl.ListFormat'
: 如果值为JavaScript内置的Intl.ListFormat
对象。'Intl.Locale'
: 如果值为JavaScript内置的Intl.Locale
对象。'Intl.NumberFormat'
: 如果值为JavaScript内置的Intl.NumberFormat
对象。'Intl.PluralRules'
: 如果值为JavaScript内置的Intl.PluralRules
对象。'Intl.RelativeTimeFormat'
: 如果值为JavaScript内置的Intl.RelativeTimeFormat
对象。'Intl.Segmenter'
: 如果值为JavaScript内置的Intl.Segmenter
对象。'MapIterator'
: 如果值为由以下函数返回的映射对象Map
的迭代器,:Map.prototype.values()
Map.prototype.keys()
Map.prototype.entries()
Map.prototype[@@iterator]()
'SetIterator'
: 如果值为由以下函数返回的集合对象Set
的迭代器:Set.prototype.values()
Set.prototype.keys()
Set.prototype.entries()
Set.prototype[@@iterator]()
'ArrayIterator'
: 如果值为由以下函数返回的数组对象Array
的迭代器:Array.prototype.values()
Array.prototype.keys()
Array.prototype.entries()
Array.prototype[@@iterator]()
TypedArray.prototype.values()
TypedArray.prototype.keys()
TypedArray.prototype.entries()
'StringIterator'
: 如果值为由以下函数返回的字符串对象String
的迭代器:String.prototype[@@iterator]()
'RegExpStringIterator'
: 如果值为由以下函数返回的正则表达式对象RegExp
的字符串迭代器:RegExp.prototype[@@matchAll]()
String.prototype.matchAll()
'SegmenterStringIterator'
: 如果值为由以下函数返回的分段对象Intel.Segmenter
的字 符串迭代器:Intl.Segmenter.prototype.segment()
返回的Segments对象的[@@iterator]()
方法。
'FinalizationRegistry'
: 如果值为JavaScript内置的FinalizationRegistry
类的对象。 一个FinalizationRegistry
对象允许您在一个值被垃圾收集时执行一个回调函数。'Arguments'
: 如果值为JavaScript内置的arguments
对象;这是一个特殊的类数组对象,存储函数的调用参数。'Generator'
: 如果值为生成器对象,即同步生成器函数返回的对象。'AsyncGenerator'
: 如果值为异步生成器对象,即异步生成器函数返回的对象。'GlobalObject'
: 如果值为[全局对象]。全局对象是始终存在于全局作用域中的对象。'Object'
: 如果值为简单的 JavaScript 对象,即通过obj = { .. }
语法定义的对象。''
(空字符串): 如果值为用户定义的匿名类的实例。value[Symbol.toStringTag]
: 如果值有自定义的Symbol.toStringTag
属性。value.constructor.name
: 如果值有具有名称的构造函数,并且名称不是'Object'
。 也就是说,如果值为用户定义的类的实例,并且该类有名称,则subtype
为该类的名称。- 从
value.toString()
中提取的名称:如果值与上述任何情况都不匹配,则subtype
是从value.toString()
结果中提取的名称(通常为'[object XXX]'
的形式), 并删除名称中的任何内部空格。例如,如果value.toString()
结果为'[object My Class ]'
, 则subtype
为'MyClass'
。
该函数支持的JavaScript内置对象的详细列表可在 Standard built-in objects 中找到。
Category
typeInfo()
返回的类型信息对象具有一个 category
属性,它是指定值的类别。
category
属性的可能值包括:
'null'
:如果值为null
。'undefined'
:如果值为undefined
。'boolean'
: 若指定的值为 primitiveboolean
值,或内置的Boolean
对象。'numeric'
: 若指定的值为 primitivenumber
值,或 primitivebigint
值,或内置的Number
对象。'string'
: 若指定的值为 primitivestring
值,或内置的String
对象。'symbol'
: 若指定的值为 primitiveSymbol
值,或内置的Boolean
对象。'function'
:如果值为函数,包括同步函数、异步函数、同步生成器函数和异步生成器函数。'regexp'
:如果值为正则表达式,即JavaScript内置的RegExp
对象。'date'
:如果值为JavaScript内置的Date
对象。'map'
:如果值为JavaScript内置的Map
对象。'set'
:如果值为JavaScript内置的Set
对象。'array'
:如果值为JavaScript内置的Array
对象。'typed-array'
:如果值为JavaScript内置的类型化数组对象,包括'Int8Array'
、'Uint8Array'
、'Uint8ClampedArray'
、'Int16Array'
、'Uint16Array'
、'Int32Array'
、'Uint32Array'
、'BigInt64Array'
、'BigUint64Array'
、'Float32Array'
和'Float64Array'
。'buffer'
:如果值为JavaScript内置的缓冲区对象,包括'ArrayBuffer'
和'SharedArrayBuffer'
。'data-view'
:如果值为JavaScript内置的DataView
对象。'weak'
:如果值为JavaScript内置的WeakMap
,WeakSet
orWeakRef
对象。注意, 弱引用对象不可被克隆。'promise'
:如果值为JavaScript内置的Promise
对象。'error'
:如果值为JavaScript内置的Error
类的对象,或Error
类的子类的对象。'intl'
:如果值为JavaScript内置的Intl
命名空间下的对象,包括'Intl.Collator'
、'Intl.DateTimeFormat'
、'Intl.DisplayNames'
、'Intl.DurationFormat'
、'Intl.ListFormat'
、'Intl.Locale'
、'Intl.NumberFormat'
、'Intl.PluralRules'
和'Intl.RelativeTimeFormat'
。'iterator'
:如果值为迭代器对象,包括'MapIterator'
、'SetIterator'
、'ArrayIterator'
、'StringIterator'
、'RegExpStringIterator'
和'SegmenterStringIterator'
。'finalization-registry'
:如果值为JavaScript内置的FinalizationRegistry
类的实例。FinalizationRegistry
对象允许您在值被垃圾回收时请求回调。'global'
:如果值为[全局对象]。'arguments'
:如果值为JavaScript内置的arguments
对象。'DOM'
: 如果值为DOM对象,包括'Node'
、'Element'
、'Document'
、'Window'
等。'CSSOM'
: 如果值为CSSOM对象,包括'CSSStyleDeclaration'
、'CSSRule'
、'CSSStyleSheet'
等。'event'
: 如果值为事件对象,包括'Event'
、'MouseEvent'
、'KeyboardEvent'
等。'console'
: 如果值为控制台对象,即'window.console'
。'file'
: 如果值为文件对象,包括'File'
、'FileList'
、'FileReader'
等。'generator'
:如果值为生成器对象,即由同步生成器函数返回的对象,包括'Generator'
和'AsyncGenerator'
。'object'
:如果值为普通的JavaScript对象。'class'
:如果值为用户定义类的实例。
特性检测常量
此库提供以下常量用于 JavaScript 引擎的特性检测:
AGGREGATEERROR_EXISTS
:JavaScript 内置类AggregateError
是否存在。ARRAYBUFFER_EXISTS
:JavaScript 内置类ArrayBuffer
是否存在。ARRAY_ISARRAY_EXISTS
:JavaScript 内置函数Array.isArray()
是否存在。ARRAY_ITERATOR_EXISTS
:JavaScript 内置函数Array.prototype[Symbol.iterator]
是否存在。ATOMICS_EXISTS
:JavaScript 内置对象Atomics
是否存在。BIGINT64ARRAY_EXISTS
:JavaScript 内置类BigInt64Array
是否存在。BIGINT_EXISTS
:JavaScript 内置原始类型bigint
和内置函数BigInt
是否存在。BIGUINT64ARRAY_EXISTS
:JavaScript 内置类BigUint64Array
是否存在。DATAVIEW_EXISTS
:JavaScript 内置类DataView
是否存在。FINALIZATIONREGISTRY_EXISTS
:JavaScript 内置类FinalizationRegistry
是否存在。FLOAT32ARRAY_EXISTS
:JavaScript 内置类Float32Array
是否存在。FLOAT64ARRAY_EXISTS
:JavaScript 内置类Float64Array
是否存在。INT16ARRAY_EXISTS
:JavaScript 内置类Int16Array
是否存在。INT32ARRAY_EXISTS
:JavaScript 内置类Int32Array
是否存在。INT8ARRAY_EXISTS
:JavaScript 内置类Int8Array
是否存在。INTERNALERROR_EXISTS
:JavaScript 内置类InternalError
是否存在。INTL_COLLATOR_EXISTS
:JavaScript 内置类Intl.Collator
是否存在。INTL_DATETIMEFORMAT_EXISTS
:JavaScript 内置类Intl.DateTimeFormat
是否存在。INTL_DISPLAYNAMES_EXISTS
:JavaScript 内置类Intl.DisplayNames
是否存在。INTL_DURATIONFORMAT_EXISTS
:JavaScript 内置类Intl.DurationFormat
是否存在。INTL_EXISTS
:JavaScript 内置Intl
命名空间是否存在。INTL_LISTFORMAT_EXISTS
:JavaScript 内置类Intl.ListFormat
是否存在。INTL_LOCALE_EXISTS
:JavaScript 内置类Intl.Locale
是否存在。INTL_NUMBERFORMAT_EXISTS
:JavaScript 内置类Intl.NumberFormat
是否存在。INTL_PLURALRULES_EXISTS
:JavaScript 内置类Intl.PluralRules
是否存在。INTL_RELATIVETIMEFORMAT_EXISTS
:JavaScript 内置类Intl.RelativeTimeFormat
是否存在。INTL_SEGMENTER_EXISTS
:JavaScript 内置类Intl.Segmenter
是否存在。INTL_SEGMENTER_ITERATOR_EXISTS
:JavaScript 内置函数Intl.Segmenter.prototype[Symbol.iterator]
是否存在。MAP_ENTRIES_EXISTS
:JavaScript 内置函数Map.prototype.entries()
是否存在。MAP_EXISTS
:JavaScript 内置类Map
是否存在。MAP_ITERATOR_EXISTS
:JavaScript 内置函数Map.prototype[Symbol.iterator]
是否存在。PROMISE_EXISTS
:JavaScript 内置类Promise
是否存在。PROXY_EXISTS
:JavaScript 内置类Proxy
是否存在。REFLECT_EXISTS
:JavaScript 内置命名空间Reflect
是否存在。REGEXP_EXISTS
:JavaScript 内置类RegExp
是否存在。REGEXP_ITERATOR_EXISTS
:JavaScript 内置函数RegExp.prototype[Symbol.matchAll]
是否存在。SET_ENTRIES_EXISTS
:JavaScript 内置函数Set.prototype.entries()
是否存在。SET_EXISTS
:JavaScript 内置类Set
是否存在。SET_ITERATOR_EXISTS
:JavaScript 内置函数Set.prototype[Symbol.iterator]
是否存在。SHAREDARRAYBUFFER_EXISTS
:JavaScript 内置类SharedArrayBuffer
是否存在。STRING_ITERATOR_EXISTS
:JavaScript 内置函数String.prototype[Symbol.iterator]
是否存在。SYMBOL_EXISTS
:JavaScript 内置Symbol
是否存在。SYMBOL_ITERATOR_EXISTS
:JavaScript 内置函数Symbol.prototype[Symbol.iterator]
是否存在。SYMBOL_MATCH_ALL_EXISTS
:JavaScript 内置函数Symbol.prototype[Symbol.matchAll]
是否存在。SYMBOL_TO_STRING_TAG_EXISTS
:JavaScript 内置函数Symbol.prototype[Symbol.toStringTag]
是否存在。UINT16ARRAY_EXISTS
:JavaScript 内置类Uint16Array
是否存在。UINT32ARRAY_EXISTS
:JavaScript 内置类Uint32Array
是否存在。UINT8ARRAY_EXISTS
:JavaScript 内置类Uint8Array
是否存在。UINT8CLAMPEDARRAY_EXISTS
:JavaScript 内置类Uint8ClampedArray
是否存在。WEAKMAP_EXISTS
:JavaScript 内置类WeakMap
是否存在。WEAKREF_EXISTS
:JavaScript 内置类WeakRef
是否存在。WEAKSET_EXISTS
:JavaScript 内置类WeakSet
是否存在。
以下代码展示如何使用这些常量:
import { WEAKMAP_EXISTS } from '@qubit-ltd/typeinfo';
function foo(value) {
if (WEAKMAP_EXISTS) {
...
} else {
...
}
}
类型原型常量
这个库为 JavaScript 内建对象的原型提供了以下常量:
AggregateErrorPrototype
:JavaScript内建AggregateError
对象的原型,如果AggregateError
类不存在,则为undefined
。ArrayBufferPrototype
:JavaScript内建ArrayBuffer
对象的原型,如果ArrayBuffer
类不存在,则为undefined
。ArrayIteratorPrototype
:JavaScript内建数组迭代器对象的原型,如果数组迭代器不存在,则为undefined
。BigInt64ArrayPrototype
:JavaScript内建BigInt64Array
对象的原型,如果BigInt64Array
类不存在,则为undefined
。BigIntPrototype
:JavaScript内建bigint
基本类型的原型,如果bigint
基本类型不存在,则为undefined
。BigUint64ArrayPrototype
:JavaScript内建BigUint64Array
对象的原型,如果BigUint64Array
类不存在,则为undefined
。DataViewPrototype
:JavaScript内建DataView
对象的原型,如果DataView
类不存在,则为undefined
。FinalizationRegistryPrototype
:JavaScript内建FinalizationRegistry
对象的原型,如果FinalizationRegistry
类不存在,则为undefined
。Float32ArrayPrototype
:JavaScript内建Float32Array
对象的原型,如果Float32Array
类不存在,则为undefined
。Float64ArrayPrototype
:JavaScript内建Float64Array
对象的原型,如果Float64Array
类不存在,则为undefined
。Int16ArrayPrototype
:JavaScript内建Int16Array
对象的原型,如果Int16Array
类不存在,则为undefined
。Int32ArrayPrototype
:JavaScript内建Int32Array
对象的原型,如果Int32Array
类不存在,则为undefined
。Int8ArrayPrototype
:JavaScript内建Int8Array
对象的原型,如果Int8Array
类不存在,则为undefined
。IntelSegmentIteratorPrototype
:JavaScript内建Intl.SegmentIterator
对象的原型,如果Intl.SegmentIterator
类不存在,则为undefined
。InternalErrorPrototype
:JavaScript内建InternalError
对象的原型,如果InternalError
类不存在,则为undefined
。IntlCollatorPrototype
:JavaScript内建Intl.Collator
对象的原型,如果Intl.Collator
类不存在,则为undefined
。IntlDateTimeFormatPrototype
:JavaScript内建Intl.DateTimeFormat
对象的原型,如果Intl.DateTimeFormat
类不存在,则为undefined
。IntlDisplayNamesPrototype
:JavaScript内建Intl.DisplayNames
对象的原型,如果Intl.DisplayNames
类不存在,则为undefined
。IntlDurationFormatPrototype
:JavaScript内建Intl.DurationFormat
对象的原型,如果Intl.DurationFormat
类不存在,则为undefined
。IntlListFormatPrototype
:JavaScript内建Intl.ListFormat
对象的原型,如果Intl.ListFormat
类不存在,则为undefined
。IntlLocalePrototype
:JavaScript内建Intl.Locale
对象的原型,如果Intl.Locale
类不存在,则为undefined
。IntlNumberFormatPrototype
:JavaScript内建Intl.NumberFormat
对象的原型,如果Intl.NumberFormat
类不存在,则为undefined
。IntlPluralRulesPrototype
:JavaScript内建Intl.PluralRules
对象的原型,如果Intl.PluralRules
类不存在,则为undefined
。IntlRelativeTimeFormatPrototype
:JavaScript内建Intl.RelativeTimeFormat
对象的原型,如果Intl.RelativeTimeFormat
类不存在,则为undefined
。IntlSegmenterPrototype
:JavaScript内建Intl.Segmenter
对象的原型,如果Intl.Segmenter
类不存在,则为undefined
。MapIteratorPrototype
:JavaScript内建Map
迭代器对象的原型,如果Map
迭代器不存在,则为undefined
。MapPrototype
:JavaScript内建Map
对象的原型,如果Map
类不存在,则为undefined
。PromisePrototype
:JavaScript内建Promise
对象的原型,如果Promise
类不存在,则为undefined
。RegExpIteratorPrototype
:JavaScript内建RegExp
迭代器对象的原型,
类型检测函数
该库提供了一组用于检查值类型的实用函数。这些函数比使用typeof
运算符或instanceof
运算符更精确可靠。
基本类型检测
import { isUndefined, isNull, isBoolean, isNumber, isString, isSymbol, isBigInt, isFunction, isObject } from '@qubit-ltd/typeinfo';
// 检查值是否为undefined
isUndefined(undefined); // true
isUndefined(null); // false
// 检查值是否为null
isNull(null); // true
isNull(undefined); // false
// 检查值是否为布尔值(原始值或对象)
isBoolean(true); // true
isBoolean(new Boolean(false)); // true
isBoolean(1); // false
// 检查值是否为数字(原始值或对象)
isNumber(42); // true
isNumber(new Number(42)); // true
isNumber('42'); // false
// 检查值是否为字符串(原始值或对象)
isString('hello'); // true
isString(new String('hello')); // true
isString(42); // false
// 检查值是否为符号
isSymbol(Symbol('foo')); // true
isSymbol('foo'); // false
// 检查值是否为bigint
isBigInt(BigInt(42)); // true
isBigInt(42); // false
// 检查值是否为函数
isFunction(() => {}); // true
isFunction({}); // false
// 检查值是否为对象
isObject({}); // true
isObject(null); // false (null不被视为对象)
isObject(42); // false
特定对象类型检测
import { isArray, isDate, isRegExp, isMap, isSet, isError, isPromise } from '@qubit-ltd/typeinfo';
// 检查值是否为数组
isArray([1, 2, 3]); // true
isArray({length: 3}); // false
// 检查值是否为日期对象
isDate(new Date()); // true
isDate('2023-01-01'); // false
// 检查值是否为正则表达式
isRegExp(/foo/); // true
isRegExp('foo'); // false
// 检查值是否为Map
isMap(new Map()); // true
isMap({}); // false
// 检查值是否为Set
isSet(new Set()); // true
isSet([]); // false
// 检查值是否为Error对象
isError(new Error()); // true
isError(new TypeError()); // true (子类也被检测)
isError({message: 'error'}); // false
// 检查值是否为Promise
isPromise(Promise.resolve()); // true
isPromise({then: () => {}}); // false (thenable对象不被视为promise)
高级类型检测
import { isPlainObject, isPrimitive, isTypedArray, isIterator, isDOMNode } from '@qubit-ltd/typeinfo';
// 检查值是否为普通对象(使用{}或new Object()创建)
isPlainObject({}); // true
isPlainObject(new Date()); // false
// 检查值是否为原始值
isPrimitive(42); // true
isPrimitive('hello'); // true
isPrimitive(Symbol('foo')); // true
isPrimitive({}); // false
// 检查值是否为类型化数组
isTypedArray(new Uint8Array()); // true
isTypedArray([]); // false
// 检查值是否为迭代器
isIterator([].values()); // true
isIterator([]); // false
// 检查值是否为DOM节点(仅在浏览器环境中)
isDOMNode(document.body); // true
isDOMNode({}); // false
这些实用函数在检查类型时使您的代码更具可读性和可靠性。它们处理边缘情况,并为整个应用程序的类型检查提供一致的接口。
跨域类型检测
JavaScript中的"域"(realm)本质上是一个隔离的执行环境,拥有自己的全局对象和内置构造函数集。在Web应用程序中,不同的域可以以各种形式存在:
- 浏览器中的不同框架(iframe)
- 浏览器中的不同窗口
- 工作线程(Web Workers、Service Workers)
- 通过Node.js的
vm
模块创建的执行上下文
当对象在域之间传递时,它们会失去与源域中构造函数的原始原型链连接。这对类型检测构成了重大挑战,因为标准方法如instanceof
在跨域边界时会失效:
// 在主域中
const mainArray = new Uint8Array(2);
console.log(mainArray instanceof Uint8Array); // true
// 在不同域中创建的对象(例如,通过Node.js中的vm.runInNewContext)
const foreignArray = runInNewContext('new Uint8Array(2)');
console.log(foreignArray instanceof Uint8Array); // false - 不同的构造函数!
这种行为可能导致应用程序处理来自不同上下文(如iframe或外部脚本)的对象时出现意外错误。
typeinfo库通过使用对象的内在特性来确定类型,而不是依赖原型链,从而解决了这个问题。这使其在跨域边界上也能可靠工作,如我们的测试所示:
// 来自type-info.typed-array.test.js
test('Int8Array across realms', () => {
const arr = runInNewContext('new Int8Array(2)');
const result = typeInfo(arr);
expect(result.type).toBe('object');
expect(result.subtype).toBe('Int8Array');
expect(result.category).toBe('typed-array');
// 其他断言...
});
该库能够正确识别对象的类型信息,无论它们的来源是什么。这种跨域能力对以下场景至关重要:
- 在iframe之间通信的Web应用程序
- 处理序列化对象的服务器应用程序
- 需要与第三方脚本中的对象协同工作的库
- 在隔离上下文中创建对象的测试环境
以下是typeinfo如何正确处理跨域类型化数组的示例:
import typeInfo from '@qubit-ltd/typeinfo';
import { runInNewContext } from 'node:vm';
// 在不同域中创建对象
const localArray = new Float32Array(4);
const foreignArray = runInNewContext('new Float32Array(4)');
// 两者返回相同的类型信息
console.log(typeInfo(localArray).subtype); // 'Float32Array'
console.log(typeInfo(foreignArray).subtype); // 'Float32Array'
// 标准的instanceof会失效
console.log(foreignArray instanceof Float32Array); // false
为何无法识别 Proxy 类型
JavaScript的Proxy
对象被设计为完全透明的,这意味着它们与它们包装的对象无法区分。根据ECMAScript规范,没有标准方法可以检测对象是否为Proxy
。
当您创建一个Proxy
对象时:
const target = {};
const handler = {};
const proxy = new Proxy(target, handler);
proxy
对象在所有方面都应该表现得与target
完全一样。因此,proxy
对象的类型信息将与target
对象的类型信息相同。
这是ECMAScript规范中的一个有意设计选择,以确保代理可以作为无需检测的替代品使用。
贡献
欢迎为typeinfo做出贡献!以下是您可以帮助的方式:
报告bug:如果您发现了bug,请创建一个issue,并详细描述如何重现它。
建议新特性:有新功能的想法?开一个issue来建议它们。
提交拉取请求:想要修复bug或实现新功能?Fork仓库,创建分支,做出更改,然后提交拉取请求。
开发设置
要设置项目进行开发:
# 克隆仓库
git clone https://github.com/Haixing-Hu/js-typeinfo.git
cd js-typeinfo
# 安装依赖
yarn install
# 运行测试
yarn test
# 构建库
yarn build
编码标准
- 遵循现有的代码风格
- 为新功能或bug修复编写测试
- 保持100%的测试覆盖率
- 更新文档以反映任何更改
许可证
typeinfo采用Apache License 2.0许可证。
Copyright 2022-2024 Haixing Hu, Qubit Co. Ltd.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.