duckie v1.3.0
duckie
A Javascript type annotation and assertion library with no dependecies. You can make it work anywhere as long as you have es5 shimed your environment.
Install
For node/browserify/webpack user, use npm install.
npm install duckieFor client user, please download the dist file in the build directory.
Example
var duckie = require('duckie');
duckie.array.test([1,2,3]) // true
duckie.array.test('123') // false
duckie.objectOf({
name: String
}).test({name: 'jack'}) // true
duckie.arrayOf({
name: String
}).test([{name: 'jack'}]) //trueExample
With duckie, it will ease all of your pain. Defining types is just like defining an object.
function post(data) {
duckie.ArrayOf({
name: String,
age: Number
}).assert(data); // if data doesn't fit the type, it will throw error
}Quick Start
Intro
All the type-checker below will contain 2 functions:
testwill return a boolean to indicate if the val belongs to the typeassertwill throw an error if the val doesn't belong to the type
For example:
duckie.array.test('abcd')will return false, andduckie.array.assert('abcd')will throw an error.
Basic Type
There are 8 basic types for you to directly use, they are:
boolstringnumberundefinednullarrayobjectanything, means any value.
example:
duckie.bool.test(true) => true
duckie.number.test(123) => true
duckie.array.test([1,2,3]) => true
duckie.array.test('hello') => falseConditional Type
oneOf(Array), any value that is one of the enums.
duckie.OneOf(['a', 'b', 'c']).test('a') // true
duckie.OneOf([1, 2, ,3]).test('a') // falseoneOfType([Type1, Type2..TypeN]), any value that belongs to one of the listed types.
duckie.oneOfType([String, Array]).test('abc') // true
duckie.oneOfType([String, Array]).test([]) // true
duckie.oneOfType([String, Array]).test(123) //falsemaybe(Type), any value that belongs to the type or exactly equals toundefinedorNaN.
duckie.maybe(String).test('abc') //true
duckie.maybe(String).test(null) // true
duckie.maybe(String).test(undefined) //true
duckie.maybe(String).test(1) // falseComposite Type
arrayOf(Type), any value that is an array and all the items in the array is typeType
duckie.arrayOf(String).test(['abc', 'bcd']) //true
duckie.arrayOf(String).test(['abc', 1]) // false, because there is a number 1 which isn't of type String
duckie.arrayOf(duckie.maybe(String)).test(['abc', null]) //true, it means array can contain string(s) or null/undefined(s)objectOf(/*definition*/), an object that contains the structure described withdefinition.
duckie.objectOf({name: String}).test({name: 'jack'}) // true
duckie.objectOf({name: String}).test({name: 'jack', age: 18}) // true, because it only check duck type
duckie.objectOf({name: String, gender: String).test({name: 'jack'}) //false, because it not contain gender
// how to describe if a field is optional? use maybe
duckie.objectOf({name: String, age: T.maybe(Number)}).test({name: 'jack'}) // true, because age is optionalComplex Type
How to desribe a data structure that:
- is an array.
- each item is a
Person - the definition of
Personis: it has a name as String, age as Number and hobbies as Array of String.
Obviously, we can combine arrayOf and ObjectOf together to achieve the goal.
// first, build an array with person type
duckie.arrayOf(Person)
// second, investigate Person type
duckie.objectOf({
name: String,
age: Number,
hobbies: duckie.arrayOf(String)
})
// finally, combine them and we get
duckie.arrayOf(duckie.objectOf{
name: String,
age: Number,
hobbies: duckie.arrayOf(String)
})Do you find it a little verbose? It looks like we are using something DSL rather than use JS. Why can't we define data structure just as defining data itself? The answer is: Yes, we can.
For arrayOf and objectOf, you don't need to wrap any type checker for inner definitions. It means:
duckie.arrayOf(duckie.objectOf({
name: String
}))
is just the same as:
duckie.arrayOf({
name: String
})so the complex definition of T.arrayOf(Person) can be written as:
duckie.arrayOf({ // omitting the objectOf makes your code cleaner
name: String,
age: Number,
hobbies: [String] // you can defined the ArrayOf(String) as [String]
})Shortcut
For the reason we may want to defined the data structure just like defining the data itself. We can use duckie(Type) to create a type checker. For Example:
duckie([]).test([1,2,3]) // the same as duckie.array.test([1,2,3])
duckie([Number]).test([1,2,3]) // the same as duckie.arrayOf(Number).test([1,2,3])
duckie({name: String}).test({name: 'jack'}) // the same as duckie.objectOf({name: String}).test({name: 'jack'})CAUTION:
duckie([Number, String])still meansduckie.arrayOf(Number)because we tend to think all the items in the array should be the same type and expressionduckie([Number, String])doesn't make any sense.
License
MIT