Another biased type checking solution for Javascript.
Exception messages may change between patch versions, as often the patch will change some behaviour that was unexpected and naturally it results in a different error message.
consttypeforce=require('typeforce')// supported primitives 'Array', 'Boolean', 'Buffer', 'Number', 'Object', 'String'typeforce('Array',[])typeforce('Number',[])// TypeError: Expected Number, got Array// array typestypeforce(['Object'],[{}])typeforce(typeforce.arrayOf('Object'),[{},{},{}])// enforces object properties typeforce({foo: 'Number'},{foo: 'bar'})// TypeError: Expected property "foo" of type Number, got String "bar"// maybe typestypeforce('?Number',2)typeforce('?Number',null)typeforce(typeforce.maybe(typeforce.Number),2)typeforce(typeforce.maybe(typeforce.Number),null)// sum typestypeforce(typeforce.anyOf('String','Number'),2)typeforce(typeforce.allOf({x: typeforce.Number},{y: typeforce.Number}),{x: 1,y: 2})// value typestypeforce(typeforce.value(3.14),3.14)// custom typesfunctionLongString(value,strict){if(!typeforce.String(value))returnfalseif(value.length!==32)returnfalsereturntrue}typeforce(LongString,'00000000000000000000000000000000')// => OK!typeforce(LongString,'not long enough')// TypeError: Expected LongString, got String 'not long enough'Protips:
// use precompiled primitives for high performancetypeforce(typeforce.Array,array)// or just precompile a templateconsttype={foo: 'Number',bar: '?String'}constfastType=typeforce.compile(type)// fastType => typeforce.object({// foo: typeforce.Number,// bar: typeforce.maybe(typeforce.String)// })// use strictness for recursive types to enforce whitelisting propertiestypeforce({x: 'Number'},{x: 1},true)// OK!typeforce({x: 'Number'},{x: 1,y: 2},true)// TypeError: Unexpected property 'y' of type NumberProtips (extended types):
typeforce(typeforce.tuple('String','Number'),['foo',1])// OK!typeforce(typeforce.tuple('Number','Number'),['not a number',1])// TypeError: Expected property "0" of type Number, got String 'not a number'typeforce(typeforce.map('Number'),{'anyKeyIsOK': 1})// OK!typeforce(typeforce.map('Number',typeforce.HexN(8)),{'deadbeef': 1,'ffff0000': 2})// OK!functionFoo(){this.x=2}typeforce(typeforce.quacksLike('Foo'),newFoo())// OK!// Note, any Foo will dotypeforce(typeforce.quacksLike('Foo'),new(functionFoo(){}))// OK!Protips (no throw)
consttypeforce=require('typeforce/nothrow')constvalue='foobar'if(typeforce(typeforce.Number,value)){// didn't throw!console.log(`${value} is a number`)// never happens}else{console.log(`Oops, ${typeforce.error.message}`)// prints 'Oops, Expected Number, got String foobar'}Protips (async)
consttypeforce=require('typeforce/async')typeforce(typeforce.Number,value,function(err){if(err)returnconsole.log(`Oops, ${typeforce.error.message}`)console.log(`${value} is a number`)// never happens})WARNING: Be very wary of using the quacksLike type, as it relies on the Foo.name property.
If that property is mangled by a transpiler, such as uglifyjs, you will have a bad time.