I’ve written micro library, to solve a very common problem in JS code today. Most likely following example looks familiar:
function Constructor(options) { options = options || {} if (typeof options.url !== 'string') throw new TypeError('url is required!') // Finally, your logic here! }
First of all, code is wrong. If falsy value is passed to a function it will misbehave. Secondly, boilerplate code makes it less readable. It takes three lines to validate just one property (very likely to have more) of the given data structure. Finally, validation code does not even belongs there, as it has nothing to do with an actual logic of a function.
What we actually need is an annotation enforcing certain constraints. We don’t have annotations in JS, but we have functions that are omnipotent! Just about everything can be solved everything using functions.
function ConstructorOptions(options) { if (options === null || options === undefined) options = {} if (typeof options !== 'object') throw new TypeError('Options must an object!') if (typeof options.url !== 'string') throw new TypeError('url is required!') } function Constructor(options) { options = ConstructorOptions(options) // Your logic here! }
This example is much better, because reader of Constructor
function can concentrate on function logic, without being distracted by a validation boilerplate. In addition, options
’ validation code can be independently unit tested and in some cases reused.
JS guards, is a small library that takes this idea to the next level. It provides declarative and recomposable way to define data type & data structure validations.
var guards = require('https://raw.github.com/Gozala/guards/v0.3.0/guards.js') // Define a { x, y } data structure, where x and y fallback to 0. var Point = guards.Schema({ x: guards.Number(0), y: guards.Number(0) }) // Define any type of guard as a function function color(value) { // If validates just return value if (typeof value === "number" && value <= 255 && value >= 0) return value // If not throw TypeError throw new TypeError("Color is a number between 0 and 255") } // Define a [0-255, 0-255, 0-255] data structure guard. var RGB = guards.Tuple([ color, color, color ]) // Compose data structure out of existing guards. var Segment = guards.Schema({ start: Point, end: Point, color: RGB, }) Segment({ end: { y: 23 }, color: [17, 255, 0] }) // { start: { x: 0, y: 0 }, end: { x: 0, y: 23 }, color: [ 17, 255, 0 ] } Segment({ start: 0, end: { y: 23 }, color: [17, 255, 0] }) // TypeError: Object expected instead of number `0` Segment({ color: [ 10, 40, '30' ]}) // TypeError: Color is a number between 0 and 255
You can use this library in browsers, jetpack and nodejs. Also, you can try it out right now via interactive example on JSFiddle. For more details and examples check out library documentation. Finally, there is a guards proposal for EcmaScript and chances are we’ll get a syntax sugar some day (It will take a while though as it’s not even in Harmony).
As always I’m more than happy to hear your feedback!