A run-time type assertion library for JavaScript. Designed to be used with Traceur.
import {assert} from 'assert';
By default, instanceof
is used to check the type.
Note that you can use assert.type()
in unit tests or anywhere in your code.
Most of the time, you will use it with Traceur.
Jump to the Traceur section to see an example of that.
describe('basic type check', function() {
class Type {}
it('should pass', function() {
assert.type(new Type(), Type);
});
it('should fail', function() {
expect(() => assert.type(123, Type))
.toThrowError('Expected an instance of Type, got 123!');
});
it('should allow null', function() {
assert.type(null, Type);
});
});
Often, instanceof
is not flexible enough.
In that case, your type can define its own assert
method which will be used instead.
See Describing More Complex Types for examples how to
define custom checks using assert.define()
.
describe('custom check', function() {
class Type {}
the basic check can just return true/false, without specifying any reason
it('should pass when returns true', function() {
Type.assert = function(value) {
return true;
};
assert.type({}, Type);
});
it('should fail when returns false', function() {
Type.assert = function(value) {
return false;
};
expect(() => assert.type({}, Type))
.toThrowError('Expected an instance of Type, got {}!');
});
Using assert.fail()
allows to report even multiple errors.
it('should fail when calls assert.fail()', function() {
Type.assert = function(value) {
assert.fail('not smart enough');
assert.fail('not blue enough');
};
expect(() => assert.type({}, Type))
.toThrowError('Expected an instance of Type, got {}!\n' +
' - not smart enough\n' +
' - not blue enough');
});
it('should fail when throws an exception', function() {
Type.assert = function(value) {
throw new Error('not long enough');
};
expect(function() {
assert.type(12345, Type);
}).toThrowError('Expected an instance of Type, got 12345!\n' +
' - not long enough');
});
});
You don’t want to check primitive values (such as strings, numbers, or booleans) using typeof
rather than
instanceof
.
Again, you probably won’t write this code and rather use Traceur to do it for you, simply based on type annotations.
describe('primitive value check', function() {
var primitive = $traceurRuntime.type;
describe('string', function() {
it('should pass', function() {
assert.type('xxx', primitive.string);
});
it('should fail', function() {
expect(() => assert.type(12345, primitive.string))
.toThrowError('Expected an instance of string, got 12345!');
});
it('should allow null', function() {
assert.type(null, primitive.string);
});
});
describe('number', function() {
it('should pass', function() {
assert.type(123, primitive.number);
});
it('should fail', function() {
expect(() => assert.type(false, primitive.number))
.toThrowError('Expected an instance of number, got false!');
});
it('should allow null', function() {
assert.type(null, primitive.number);
});
});
describe('boolean', function() {
it('should pass', function() {
assert.type(true, primitive.boolean);
assert.type(false, primitive.boolean);
});
it('should fail', function() {
expect(() => assert.type(123, primitive.boolean))
.toThrowError('Expected an instance of boolean, got 123!');
});
it('should allow null', function() {
assert.type(null, primitive.boolean);
});
});
});
Often, a simple type check using instanceof
or typeof
is not enough.
That’s why you can define custom checks using this DSL.
The goal was to make them easy to compose and as descriptive as possible.
Of course you can write your own DSL on the top of this.
describe('define', function() {
If the first argument to assert.define()
is a type (function), it will define assert
method on that function.
In this example, being a type of Type means being a either a function or object.
it('should define assert for an existing type', function() {
class Type {}
assert.define(Type, function(value) {
assert(value).is(Function, Object);
});
assert.type({}, Type);
assert.type(function() {}, Type);
expect(() => assert.type('str', Type))
.toThrowError('Expected an instance of Type, got "str"!\n' +
' - "str" is not instance of Function\n' +
' - "str" is not instance of Object');
});
If the first argument to assert.define()
is a string,
it will create an interface - basically an empty class with assert
method.
it('should define an interface', function() {
var User = assert.define('MyUser', function(user) {
assert(user).is(Object);
});
assert.type({}, User);
expect(() => assert.type(12345, User))
.toThrowError('Expected an instance of MyUser, got 12345!\n' +
' - 12345 is not instance of Object');
});
Here are a couple of more APIs to describe your custom types…
Checks if the value is an array and if so, it checks whether all the items are one the given types. These types can be composed types, not just simple ones.
describe('arrayOf', function() {
var Titles = assert.define('ListOfTitles', function(value) {
assert(value).is(assert.arrayOf(assert.string, assert.number));
});
it('should pass', function () {
assert.type(['one', 55, 'two'], Titles);
});
it('should fail when non-array given', function () {
expect(() => assert.type('foo', Titles))
.toThrowError('Expected an instance of ListOfTitles, got "foo"!\n' +
' - "foo" is not instance of array of string/number\n' +
' - "foo" is not instance of Array');
});
it('should fail when an invalid item in the array', function () {
expect(() => assert.type(['aaa', true], Titles))
.toThrowError('Expected an instance of ListOfTitles, got ["aaa", true]!\n' +
' - ["aaa", true] is not instance of array of string/number\n' +
' - true is not instance of string\n' +
' - true is not instance of number');
});
});
Similar to assert.arrayOf
which checks a content of an array,
assert.structure
checks if the value is an object with specific properties.
describe('structure', function() {
var User = assert.define('MyUser', function(value) {
assert(value).is(assert.structure({
name: assert.string,
age: assert.number
}));
});
it('should pass', function () {
assert.type({name: 'Vojta', age: 28}, User);
});
it('should fail when non-object given', function () {
expect(() => assert.type(123, User))
.toThrowError('Expected an instance of MyUser, got 123!\n' +
' - 123 is not instance of object with properties name, age\n' +
' - 123 is not instance of Object');
});
it('should fail when an invalid property', function () {
expect(() => assert.type({name: 'Vojta', age: true}, User))
.toThrowError('Expected an instance of MyUser, got {name: "Vojta", age: true}!\n' +
' - {name: "Vojta", age: true} is not instance of object with properties name, age\n' +
' - true is not instance of number');
});
});
});
Manually calling assert.type()
in your code is cumbersome. Most of the time, you’ll want to
have Traceur add the calls to assert.type()
to your code based on type annotations.
This has several advantages:
You’ll need to run Traceur with --types=true --type-assertions=true --type-assertion-module="path/to/assert"
.
describe('Traceur', function() {
describe('arguments', function() {
function reverse(str: string) {
return str ? reverse(str.substring(1)) + str[0] : ''
}
it('should pass', function() {
expect(reverse('angular')).toBe('ralugna');
});
it('should fail', function() {
expect(() => reverse(123))
.toThrowError('Invalid arguments given!\n' +
' - 1st argument has to be an instance of string, got 123');
});
});
describe('return value', function() {
function foo(bar): number {
return bar;
}
it('should pass', function() {
expect(foo(123)).toBe(123);
});
it('should fail', function() {
expect(() => foo('bar'))
.toThrowError('Expected to return an instance of number, got "bar"!');
});
});
describe('variables', function() {
it('should pass', function() {
var count:number = 1;
});
it('should fail', function() {
expect(() => {
var count: number = true;
}).toThrowError('Expected an instance of number, got true!');
});
});
describe('void', function() {
function foo(bar): void {
return bar;
}
it('should pass when not defined', function() {
function nonReturn(): void {}
function returnNothing(): void { return; }
function returnUndefined(): void { return undefined; }
foo();
foo(undefined);
nonReturn();
returnNothing();
returnUndefined();
});
it('should fail when a value returned', function() {
expect(() => foo('bar'))
.toThrowError('Expected to return an instance of voidType, got "bar"!');
});
it('should fail when null returned', function() {
expect(() => foo(null))
.toThrowError('Expected to return an instance of voidType, got null!');
});
});
});