类型判断 a / an / typeOf / instanceof - 检查值的类型信息
三种类型断言方法
Chai 提供三个不同粒度的类型检查断言:
| 方法 | 检查内容 | 参数 | 示例 |
|---|---|---|---|
.a / .an | typeof 类型字符串 | 类型小写字符串 | expect(x).to.be.a('string') |
.typeOf | 同 .a / .an(别名) | 类型小写字符串 | expect(x).to.typeOf('number') |
.instanceOf / .instanceof | 原型链 | 构造函数 | expect(x).to.be.an.instanceOf(Error) |
.a / .an 的区别
两者完全等价,根据后面的类型字符串发音选择:
expect('hello').to.be.a('string'); // 'string' 辅音开头 → a
expect(42).to.be.a('number'); // 'number' 辅音开头 → a
expect([1,2]).to.be.an('array'); // 'array' 元音开头 → an
expect(null).to.be.a('null'); // 'null' 辅音开头 → a
这完全是可读性的语法糖——用错 a/an 不会导致断言失败。expect('hello').to.be.an('string') 照样通过。
支持的 typeof 类型字符串
// 原始类型
expect('hello').to.be.a('string');
expect(42).to.be.a('number');
expect(true).to.be.a('boolean');
expect(undefined).to.be.an('undefined');
expect(null).to.be.a('null');
// 注意:typeof null 在 JS 中返回 'object',但 Chai 做了特殊处理
// expect(null).to.be.a('object') 会失败
// expect(null).to.be.a('null') 才是正确的
// 函数
expect(function() {}).to.be.a('function');
expect(async () => {}).to.be.a('function');
expect(() => 1).to.be.a('function');
// 符号和 BigInt
expect(Symbol('x')).to.be.a('symbol');
expect(1n).to.be.a('bigint');
// 对象和数组
expect({}).to.be.an('object');
expect([]).to.be.an('array'); // array 不是 object!Chai 特殊处理
expect(/regex/).to.be.an('object'); // RegExp 是 object
expect(new Date()).to.be.an('object');
.typeOf 方法形式
如果你更喜欢方法调用形式(assert 风格的接口):
expect('hello').to.be.typeOf('string'); // 方法形式
// 等价于
expect('hello').to.be.a('string'); // 属性形式
两者功能完全相同。
.instanceOf 检查原型链
.instanceOf 对应 JavaScript 的 instanceof 运算符:
class Animal {}
class Dog extends Animal {}
const dog = new Dog();
expect(dog).to.be.an.instanceOf(Dog); // 通过
expect(dog).to.be.an.instanceOf(Animal); // 通过(原型链)
expect(dog).to.be.an.instanceOf(Object); // 通过(所有对象都是 Object 实例)
注意:.instanceof 也是合法的别名(少一个 f):
expect(error).to.be.an.instanceof(Error);
大小写也不敏感:.instanceOf / .instanceof / .InstanceOf 都行。
null 和 undefined 的特殊处理
JavaScript 的 typeof null 历史遗留问题——返回 'object'。Chai 为此做了特殊处理:
// ✅ 正确
expect(null).to.be.a('null');
expect(undefined).to.be.an('undefined');
// ❌ 会失败
expect(null).to.be.an('object'); // Chai 识别 null 的特殊性
这是 Chai 帮你处理的常见陷阱之一。
.not + 类型检查
expect(42).to.not.be.a('string');
expect({}).to.not.be.an('array');
expect(err).to.not.be.an.instanceOf(TypeError);
类型组合检查
一次检查多个类型:
// 用 .satisfy 自定义谓词
expect(value).to.satisfy(v => typeof v === 'string' || typeof v === 'number');
// 或者先检查值再检查类型
if (typeof value === 'string') {
expect(value).to.match(/^\d+$/);
} else {
expect(value).to.be.a('number');
}
assert 风格中的类型检查
const assert = require('chai').assert;
assert.typeOf(value, 'string');
assert.notTypeOf(value, 'number');
assert.instanceOf(obj, SomeClass);
assert.notInstanceOf(obj, SomeClass);
Array 是一个特殊类型
注意在 Chai 中,数组的类型是 'array' 而不是 'object':
expect([]).to.be.an('array'); // 通过
expect([]).to.be.an('object'); // 失败
这符合直觉但不完全等同于原生 JS 行为(typeof [] 返回 'object')。Chai 做了这个改进。