Effective type checking in plain javascript.
npm install type.ofsh
npm install type.of
`Expressive syntax:
`js
function person(name, weight, children) { TYPEOF
(...arguments)
(String, Number, Array)
// ...
}
`Nice messages:
`
TypeError: (2) required: number
Provided: string
(3) required: array
Provided: { name:string, weight:number, children:array }
at yourFunction (/Users/.../yourFile.js:10:7)
at /Users/.../yourFile.js:13:3
at Object. (/Users/.../yourFile.js:15:2)
at Module._compile (module.js:541:32)
at Object.Module._extensions..js (module.js:550:10)
at Module.load (module.js:458:32)
...
`Javascript is hostile to effective type checking.
`js
typeof null // object >:(typeof NaN // number :?
NaN === NaN // false >:(
typeof [1, 2] // object >:(
's' instanceof String // false :/
5 instanceof Number // false :/
true instanceof Boolean // false :/
`Gotchas make manual type validation logic categorically unmaintainable. And even if it were maintainable, thorough checks are grotesque.
TYPEOF reduces all this to rote declaration:`js
function person(name, weight, children) { TYPEOF
(...arguments)
(String, Number, Array)
// ...
}
`We fix the gotchas, and when mismatches happen, there's no detective work:
`
TypeError: (2) required: number
provided: string
at yourFunction (/Users/.../yourFile.js:10:7)
at /Users/.../yourFile.js:13:3
at Object. (/Users/.../yourFile.js:15:2)
at Module._compile (module.js:541:32)
at Object.Module._extensions..js (module.js:550:10)
at Module.load (module.js:458:32)
...
`API
$3
TYPEOF implements pairwise type validation with Curry syntax:`js
TYPEOF(val1, ..., valN)(type1, ..., typeN)
`So, validating a single value is just the limiting case:
`js
function isYoung(age) { TYPEOF(age)(Number)
return age < 80
}
`Array-like iterables (i.e., arrays and native arguments objects) can be validated concisely using the spread operator, as follows:
`js
function example(name, age, isTall) { TYPEOF
(...arguments)
(String, Number, Boolean)
// Do stuff.
}
`Type validation calls return the first value passed, so function return types can be validated easily:
`js
function divide(num1, num2) {
return TYPEOF(num1 / num2)(Number)
}divide(10, 2) // returns 5
divide(10, undefined) // throws
`$3
#### Native and custom types work.`js
TYPEOF(val)(ArrayBuffer)
TYPEOF(val)(MyClass)
TYPEOF(val)('MyClass') // <-- By name works too.
`#### Duck types work.
Specify any subset of keys and corresponding types to duck type a value.
`js
TYPEOF
(val)
({ name:String, weight:Number })
`TypeErrors produce description diffs of the form:
`
TypeError: (1) required: { name:string, weight:number, ... }
provided: { name:number, weight:string, ... }
...
`#### Disjoint types work.
Use arrays to express that any of the given types is valid.
`js
TYPEOF(val)([String, Number])
`TypeErrors produce description diffs of the form:
`
TypeError: (1) required: string|number
provided: null
...
`#### You can declare
'void' and 'any'.`js
function example() { TYPEOF
(...arguments)
('void')
// Do whatever.
}
`Or permit any type:
`js
TYPEOF(val)('any')
`#### Mix and nest as necessary.
`js
TYPEOF
(...arguments)
([MyClass, String], { prop:MyClass, prop2:'any' }, 'MyClass')
`$3
Define complex types with
TYPEOF.DFN() for DRY-ness and concision. Here we'll describe the signature of a middleware function:`js
TYPEOF.DFN('req', { originalUrl:String, method:String })
TYPEOF.DFN('res', { headersSent:Boolean, locals:Object })
`And we can use it anywhere:
`js
// ./some-middleware.js
function myMiddleware(req, res, next) { TYPEOF
(...arguments)
('req', 'res', Function)
// Do whatever...
}
`It's powerfully wily. You can define functions to check types when you need to do something weird, like check that a value isn't of a particular type, for example:
`js
TYPEOF.DFN('not Object', val => !(val instanceof Object), true)TYPEOF({})('not Object') // throws
`Passing
true as the third parameter tells TYPEOF that the notObject function should be invoked to check the type, taking the value being checked as the sole argument.$3
Use
TYPEOF.WARN() to have TYPEOF merely report TypeErrors in the console. (This is useful when refactoring.)$3
TYPEOF.OFF() Disables all type checking, eliminates the (negligible) performance hit of the type checks, and prevents throw-ing. (This is useful in production.)$3
Call
TYPEOF.ONFAIL(callback)` and pass a callback to implement remote logging (or whatever). When an error is encountered, it will be passed to your function.