Skip to content

Instantly share code, notes, and snippets.

@ctrlplusb
Created January 20, 2016 21:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ctrlplusb/cdffa1fc1b14f427b790 to your computer and use it in GitHub Desktop.
Save ctrlplusb/cdffa1fc1b14f427b790 to your computer and use it in GitHub Desktop.
Using tcomb to type check your functions without annotations.
import { isType } from 'tcomb';
/**
* (...values) => (...types) => value||[values]
*
* This is a curried function to help with type checking your javascript.
* It is curried in two parts, the first part taking the values that you
* wish to type check, the second part of the curry takes the types you wish
* to validate them with.
*
* If your types are valid then your values are returned. In the case of there
* being multiple values the values shall be returned within an Array. In the
* case of there being a single value the single value shall be returned, this
* makes tCheck useful for function input and return values.
*
* @example
* const example = (var1, var2) => {
* tCheck(var1, var2)(t.String, t.String);
*
* const result = var1 + var2;
*
* return tCheck(result)(t.String);
* };
*
* example('foo', 'bar'); // foobar
*
*
* @throws {Error} If the values or args are empty, or are different lengths,
* or if the given types are not valid tcomb types.
* @throws {TypeError} If the values do not match the expected types.
*
* @return {value(s)} The single value if a single value was given, else
* multiple values are returned within an Array.
*/
const tCheck = function values() {
const valueArgs = arguments;
/**
* If running in production mode we shall disable the type checking for
* performance reasons.
*/
if (process.env.NODE_ENV === 'production') {
return () => {
if (valueArgs.length === 0) {
return void 0;
}
const valueArgsArr = Array.prototype.slice.call(valueArgs);
return valueArgsArr.length > 1 ? valueArgsArr : valueArgsArr[0];
};
}
return function types() {
const typeArgs = arguments;
if (valueArgs.length === 0) {
throw new Error(
'No "values" provided to tCheck.'
);
}
if (typeArgs.length === 0) {
throw new Error(
'No "types" provided to tCheck.'
);
}
if (valueArgs.length !== typeArgs.length) {
throw new Error(
'The "values" and "types" provided to tCheck have different lengths.'
);
}
const typeArgsArr = Array.prototype.slice.call(typeArgs);
typeArgsArr.forEach((x) => {
if (!isType(x)) {
throw new Error(
'The "types" provied to tCheck should be valid "tcomb" types.'
);
}
});
const valueArgsArr = Array.prototype.slice.call(valueArgs);
for (let i = 0; i < valueArgsArr.length; i++) {
typeArgsArr[i](valueArgsArr[i]);
}
if (valueArgsArr.length === 1) {
return valueArgsArr[0];
}
return valueArgsArr;
};
};
export default tCheck;
import { expect } from 'chai';
import t from 'tcomb';
describe(`Given the tCheck util`, () => {
describe('When running in a non-production environment', () => {
let tCheck;
before(() => {
process.env.NODE_ENV = 'test';
tCheck = require('./tCheck.js').default;
});
it('Should fail for no value arguments', () => {
expect(() => tCheck()(t.String)).to.throw(Error, /No "values" provided/);
});
it('Should fail for no type arguments', () => {
expect(() => tCheck('foo')()).to.throw(Error, /No "types" provided/);
});
it('Should fail for arguments of different lengths', () => {
expect(() => tCheck('foo', true)(t.String)).to.throw(Error, /different lengths/);
});
it('Should fail for type arguments that not valid tcomb types', () => {
expect(() => tCheck('foo')({})).to.throw(Error, /should be valid "tcomb" types/);
});
it('Should fail when values are not of the expected type', () => {
expect(() => tCheck('foo')(t.Number)).to.throw(TypeError);
});
it('Should fail when values are not of the expected type (n args)', () => {
expect(() => tCheck('foo', 1)(t.String, t.String)).to.throw(TypeError);
});
it('Should return the actual value when a valid tCheck is performed for a single value', () => {
expect(tCheck('foo')(t.String)).to.equal('foo');
});
it('Should return an Array containing the values when a valid tCheck is performed for multiple values', () => {
const result = tCheck('foo', 1)(t.String, t.Number);
expect(result).to.be.an.instanceof(Array);
expect(result[0]).to.equal('foo');
expect(result[1]).to.equal(1);
});
it('Example correct implementation should return the correct result', () => {
const example = (var1, var2) => {
tCheck(var1, var2)(t.String, t.String);
const result = var1 + var2;
return tCheck(result)(t.String);
};
const result = example('foo', 'bar');
expect(result).to.equal('foobar');
});
});
describe('When running in a production environment', () => {
let tCheck;
before(() => {
process.env.NODE_ENV = 'production';
tCheck = require('./tCheck.js').default;
});
it('Should not fail for no value arguments', () => {
expect(() => tCheck()(t.String)).to.not.throw(Error);
});
it('Should not fail for no type arguments', () => {
expect(() => tCheck('foo')()).to.not.throw(Error);
});
it('Should not fail for arguments of different lengths', () => {
expect(() => tCheck('foo', true)(t.String)).to.not.throw(Error);
});
it('Should not fail for type arguments that not valid tcomb types', () => {
expect(() => tCheck('foo')({})).to.not.throw(Error);
});
it('Should not fail when values are not of the expected type', () => {
expect(() => tCheck('foo')(t.Number)).to.not.throw(TypeError);
});
it('Should not fail when values are not of the expected type (n args)', () => {
expect(() => tCheck('foo', 1)(t.String, t.String)).to.not.throw(TypeError);
});
it('Should return undefined when no value is provided', () => {
expect(tCheck()()).to.equal(undefined);
});
it('Should return the actual value when a single value is provided', () => {
expect(tCheck('foo')()).to.equal('foo');
});
it('Should return an Array containing the values when multiple values are provided', () => {
const result = tCheck('foo', 1)();
expect(result).to.be.an.instanceof(Array);
expect(result[0]).to.equal('foo');
expect(result[1]).to.equal(1);
});
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment