Comparing version 2.0.1 to 2.1.0
@@ -14,2 +14,8 @@ # Changelog | ||
## v2.1.0 | ||
- **New Feature** | ||
- added aliases for pre-defined irreducible types fix #112 | ||
- added overridable `stringify` function to handle error messages and improve performances in development (replaces the experimental `options.verbose`) | ||
## v2.0.1 | ||
@@ -16,0 +22,0 @@ |
171
GUIDE.md
@@ -9,2 +9,6 @@ # Setup | ||
```js | ||
import t from 'tcomb'; | ||
``` | ||
# The idea | ||
@@ -24,11 +28,11 @@ | ||
* `Str`: strings | ||
* `Num`: numbers | ||
* `Bool`: booleans | ||
* `Arr`: arrays | ||
* `Obj`: plain objects | ||
* `Func`: functions | ||
* `Err`: errors | ||
* `Re`: regular expressions | ||
* `Dat`: dates | ||
* `t.String`: strings (short alias `t.Str`) | ||
* `t.Number`: numbers (short alias `t.Num`) | ||
* `t.Boolean`: booleans (short alias `t.Bool`) | ||
* `t.Array`: arrays (short alias `t.Arr`) | ||
* `t.Object`: plain objects (short alias `t.Obj`) | ||
* `t.Function`: functions (short alias `t.Func`) | ||
* `t.Error`: errors (short alias `t.Err`) | ||
* `t.RegExp`: regular expressions (short alias `t.Re`) | ||
* `t.Date`: dates (short alias `t.Dat`) | ||
@@ -39,4 +43,4 @@ There are 2 additional irriducible types defined in tcomb: | ||
* `Nil`: `null` or `undefined` | ||
* `Any`: any type | ||
* `t.Nil`: `null` or `undefined` | ||
* `t.Any`: any type | ||
@@ -50,7 +54,7 @@ ## Type checking with the `is` function | ||
t.Str.is('a string'); // => true | ||
t.Str.is(1); // => false | ||
t.String.is('a string'); // => true | ||
t.String.is(1); // => false | ||
t.Num.is('a string'); // => false | ||
t.Num.is(1); // => true | ||
t.Number.is('a string'); // => false | ||
t.Number.is(1); // => true | ||
@@ -65,4 +69,4 @@ // and so on... | ||
```js | ||
assert(Str.is('a string')); // => ok | ||
assert(Str.is(1)); // => throws | ||
assert(t.String.is('a string')); // => ok | ||
assert(t.String.is(1)); // => throws | ||
``` | ||
@@ -83,4 +87,4 @@ | ||
```js | ||
const s1 = Str('a string'); // => ok | ||
const s2 = Str(1); // => throws | ||
const s1 = t.String('a string'); // => ok | ||
const s2 = t.String(1); // => throws | ||
``` | ||
@@ -104,4 +108,4 @@ | ||
function Point (x, y) { | ||
this.x = Num(x); | ||
this.y = Num(y); | ||
this.x = t.Number(x); | ||
this.y = t.Number(y); | ||
} | ||
@@ -132,3 +136,3 @@ | ||
Example: the `meta` object of `Str`: | ||
Example: the `meta` object of `t.String`: | ||
@@ -138,3 +142,3 @@ ```js | ||
kind: 'irreducible', | ||
is: function isStr(x) { | ||
is: function isString(x) { | ||
return typeof x === 'string'; | ||
@@ -165,3 +169,3 @@ } | ||
// defines a type representing positive numbers | ||
const Positive = t.subtype(t.Num, n => return n >= 0, 'Positive'); | ||
const Positive = t.subtype(t.Number, (n) => n >= 0, 'Positive'); | ||
@@ -210,4 +214,4 @@ Positive.is(1); // => true | ||
* `keys: Array<Str|Number> | Str` is the array of enums or a string where the enums are separated by spaces | ||
* `name: ?Str` is an optional string useful for debugging purposes | ||
* `keys: Array<string|number> | string` is the array of enums or a string where the enums are separated by spaces | ||
* `name: ?string` is an optional string useful for debugging purposes | ||
@@ -237,4 +241,4 @@ ```js | ||
const Point = t.struct({ | ||
x: Num, | ||
y: Num | ||
x: t.Number, | ||
y: t.Number | ||
}, 'Point'); | ||
@@ -277,3 +281,3 @@ | ||
```js | ||
const Point3D = Point.extend({z: Num}, 'Point3D'); | ||
const Point3D = Point.extend({z: t.Number}, 'Point3D'); | ||
@@ -291,5 +295,5 @@ // multiple inheritance | ||
```js | ||
const Rectangle = struct({ | ||
width: Num, | ||
height: Num | ||
const Rectangle = t.struct({ | ||
width: t.Number, | ||
height: t.Number | ||
}); | ||
@@ -302,3 +306,3 @@ | ||
const Cube = Rectangle.extend({ | ||
thickness: Num | ||
thickness: t.Number | ||
}); | ||
@@ -315,3 +319,3 @@ | ||
```js | ||
const Wrong = Point.extend({x: Num}); // => throws | ||
const Wrong = Point.extend({x: t.Number}); // => throws | ||
``` | ||
@@ -329,3 +333,3 @@ | ||
```js | ||
const Area = tuple([Num, Num]); | ||
const Area = t.tuple([t.Number, t.Number]); | ||
@@ -355,3 +359,3 @@ // constructor usage, `area` is immutable | ||
```js | ||
const Path = list(Point); | ||
const Path = t.list(Point); | ||
@@ -385,3 +389,3 @@ // costructor usage, `path` is immutable | ||
```js | ||
const Tel = dict(Str, Num); | ||
const Tel = dict(String, t.Number); | ||
@@ -410,3 +414,3 @@ // costructor usage, `tel` is immutable | ||
```js | ||
const ReactKey = union([Str, Num]); | ||
const ReactKey = t.union([t.String, t.Number]); | ||
@@ -439,4 +443,4 @@ ReactKey.is('a'); // => true | ||
ReactKey.dispatch = function (x) { | ||
if (Str.is(x)) return Str; | ||
if (Num.is(x)) return Num; | ||
if (t.String.is(x)) return t.String; | ||
if (t.Number.is(x)) return t.Number; | ||
}; | ||
@@ -461,3 +465,3 @@ | ||
// the value of a radio input where null = no selection | ||
const Radio = maybe(Str); | ||
const Radio = t.maybe(t.String); | ||
@@ -483,4 +487,4 @@ Radio.is('a'); // => true | ||
```js | ||
// add takes two `Num`s and returns a `Num` | ||
const add = func([Num, Num], Num) | ||
// add takes two `t.Number`s and returns a `t.Number` | ||
const add = t.func([t.Number, t.Number], t.Number) | ||
.of(function (x, y) { return x + y; }); | ||
@@ -492,4 +496,4 @@ ``` | ||
```js | ||
add("Hello", 2); // Raises error: Invalid `Hello` supplied to `Num` | ||
add("Hello"); // Raises error: Invalid `Hello` supplied to `Num` | ||
add("Hello", 2); // Raises error: Invalid `Hello` supplied to `t.Number` | ||
add("Hello"); // Raises error: Invalid `Hello` supplied to `t.Number` | ||
@@ -511,4 +515,4 @@ add(1, 2); // Returns: 3 | ||
```js | ||
// An `A` takes a `Str` and returns an `Num` | ||
const A = func(Str, Num); | ||
// An `A` takes a `t.String` and returns an `t.Number` | ||
const A = t.func(t.String, t.Number); | ||
``` | ||
@@ -519,10 +523,10 @@ | ||
```js | ||
// A `B` takes a `Func` (which takes a `Str` and returns a `Num`) and returns a `Str`. | ||
const B = func(func(Str, Num), Str); | ||
// A `B` takes a `Func` (which takes a `t.String` and returns a `t.Number`) and returns a `t.String`. | ||
const B = t.func(t.func(t.String, t.Number), t.String); | ||
// An `ExcitedStr` is a `Str` containing an exclamation mark | ||
const ExcitedStr = subtype(Str, function (s) { return s.indexOf('!') !== -1; }, 'ExcitedStr'); | ||
// An `ExcitedString` is a `t.String` containing an exclamation mark | ||
const ExcitedString = t.subtype(t.String, function (s) { return s.indexOf('!') !== -1; }, 'ExcitedString'); | ||
// An `Exciter` takes a `Str` and returns an `ExcitedStr` | ||
const Exciter = func(Str, ExcitedStr); | ||
// An `Exciter` takes a `t.String` and returns an `ExcitedString` | ||
const Exciter = t.func(t.String, ExcitedString); | ||
``` | ||
@@ -533,4 +537,4 @@ | ||
```js | ||
// A `C` takes an `A`, a `B` and a `Str` and returns a `Num` | ||
const C = func([A, B, Str], Num); | ||
// A `C` takes an `A`, a `B` and a `t.String` and returns a `t.Number` | ||
const C = t.func([A, B, t.String], t.Number); | ||
``` | ||
@@ -563,6 +567,6 @@ | ||
// Raises error: | ||
// Invalid `Hello?` supplied to `ExcitedStr`, insert a valid value for the subtype | ||
// Invalid `Hello?` supplied to `ExcitedString`, insert a valid value for the subtype | ||
simpleQuestionator('Hello'); | ||
// Raises error: Invalid `1` supplied to `Str` | ||
// Raises error: Invalid `1` supplied to `String` | ||
simpleExciter(1); | ||
@@ -578,7 +582,7 @@ | ||
// We can reasonably suggest that add has the following type signature | ||
// add : Num -> Num -> Num | ||
const add = func([Num, Num], Num) | ||
// add : t.Number -> t.Number -> t.Number | ||
const add = t.func([t.Number, t.Number], t.Number) | ||
.of(function (x, y) { return x + y }, true); | ||
const addHello = add("Hello"); // As this raises: "Error: Invalid `Hello` supplied to `Num`" | ||
const addHello = add("Hello"); // As this raises: "Error: Invalid `Hello` supplied to `t.Number`" | ||
@@ -603,4 +607,4 @@ const add2 = add(2); | ||
func([Num, Num], Num).is(func([Num, Num], Num).of(id)); // Returns: true | ||
func([Num, Num], Num).is(func(Num, Num).of(id)); // Returns: false | ||
t.func([t.Number, t.Number], t.Number).is(func([t.Number, t.Number], t.Number).of(id)); // Returns: true | ||
t.func([t.Number, t.Number], t.Number).is(func(t.Number, t.Number).of(id)); // Returns: false | ||
``` | ||
@@ -616,6 +620,6 @@ | ||
You can update an immutable instance with the `update` static function | ||
You can update an immutable instance with the provided `update` function: | ||
```js | ||
Type.update(instance, spec) | ||
MyType.update(instance, spec) | ||
``` | ||
@@ -625,8 +629,8 @@ | ||
* $push | ||
* $unshift | ||
* $splice | ||
* $set | ||
* $apply | ||
* $merge | ||
* `$push` | ||
* `$unshift` | ||
* `$splice` | ||
* `$set` | ||
* `$apply` | ||
* `$merge` | ||
@@ -644,5 +648,5 @@ Example: | ||
```js | ||
const Type = dict(Str, Num); | ||
const instance = Type({a: 1, b: 2}); | ||
const updated = Type.update(instance, {$remove: ['a']}); // => {b: 2} | ||
const MyType = dict(t.String, t.Number); | ||
const instance = MyType({a: 1, b: 2}); | ||
const updated = MyType.update(instance, {$remove: ['a']}); // => {b: 2} | ||
``` | ||
@@ -653,5 +657,5 @@ | ||
```js | ||
const Type = list(Num); | ||
const instance = Type([1, 2, 3, 4]); | ||
const updated = Type.update(instance, {'$swap': {from: 1, to: 2}}); // => [1, 3, 2, 4] | ||
const MyType = list(t.Number); | ||
const instance = MyType([1, 2, 3, 4]); | ||
const updated = MyType.update(instance, {'$swap': {from: 1, to: 2}}); // => [1, 3, 2, 4] | ||
``` | ||
@@ -700,3 +704,3 @@ | ||
```js | ||
getTypeName(Str); // => 'Str' | ||
t.getTypeName(String); // => 'String' | ||
``` | ||
@@ -711,6 +715,15 @@ | ||
```js | ||
mixin({a: 1}, {b: 2}); // => {a: 1, b: 2} | ||
mixin({a: 1}, {a: 2}); // => throws | ||
t.mixin({a: 1}, {b: 2}); // => {a: 1, b: 2} | ||
t.mixin({a: 1}, {a: 2}); // => throws | ||
``` | ||
...unless `override = true` | ||
## stringify(x: any): String | ||
Used internally to format the error messages. Since it uses by default `JSON.stringify` and can be slow in a performance intensive application so you may want to override it: | ||
```js | ||
// override with a less verbose but much faster function | ||
t.stringify = String; | ||
``` |
116
index.js
'use strict'; | ||
exports.options = { | ||
verbose: true | ||
}; | ||
function stringify(x) { | ||
// set options.verbose = false to improve performances in development | ||
if (!exports.options.verbose) { | ||
return String(x); | ||
} | ||
try { // handle "Converting circular structure to JSON" error | ||
@@ -19,2 +11,4 @@ return JSON.stringify(x, null, 2); | ||
exports.stringify = stringify; | ||
function isInstanceOf(x, constructor) { | ||
@@ -85,3 +79,3 @@ return x instanceof constructor; | ||
// type should be a class constructor and value some instance, just check membership and return the value | ||
assert(isInstanceOf(value, type), 'The value ' + stringify(value) + ' is not an instance of ' + getFunctionName(type)); | ||
assert(isInstanceOf(value, type), 'The value ' + exports.stringify(value) + ' is not an instance of ' + getFunctionName(type)); | ||
} | ||
@@ -104,3 +98,3 @@ | ||
exports.fail = function fail(message) { | ||
throw new TypeError(message); | ||
throw new TypeError('[tcomb] ' + message); | ||
}; | ||
@@ -110,8 +104,6 @@ | ||
if (guard !== true) { | ||
exports.fail(message || 'assert failed'); | ||
exports.fail(message || 'Assert failed'); | ||
} | ||
} | ||
var slice = Array.prototype.slice; | ||
// safe mixin: cannot override props unless specified | ||
@@ -124,3 +116,3 @@ function mixin(target, source, overwrite) { | ||
if (process.env.NODE_ENV !== 'production') { | ||
assert(!target.hasOwnProperty(k), 'Cannot overwrite property ' + k + ' in mixin(' + stringify(target) + ', ' + stringify(source) + ')'); | ||
assert(!target.hasOwnProperty(k), 'Invalid call to mixin(): cannot overwrite property ' + exports.stringify(k) + ' of target object'); | ||
} | ||
@@ -150,3 +142,3 @@ } | ||
if (process.env.NODE_ENV !== 'production') { | ||
assert(isObject(spec), 'Invalid argument spec = ' + stringify(spec) + ' supplied to function update(instance, spec): expected an object'); | ||
assert(isObject(spec), 'Invalid argument spec = ' + exports.stringify(spec) + ' supplied to function update(instance, spec): expected an object containing commands'); | ||
} | ||
@@ -244,3 +236,3 @@ | ||
if (process.env.NODE_ENV !== 'production') { | ||
assert(isString(name), 'Invalid argument name = ' + stringify(name) + ' supplied to irreducible(name, predicate)'); | ||
assert(isString(name), 'Invalid argument name = ' + exports.stringify(name) + ' supplied to irreducible(name, predicate)'); | ||
assert(isFunction(predicate), 'Invalid argument predicate supplied to irreducible(name, predicate)'); | ||
@@ -253,3 +245,3 @@ } | ||
forbidNewOperator(this, Irreducible); | ||
assert(predicate(value), 'Invalid argument value = ' + stringify(value) + ' supplied to irreducible type ' + name); | ||
assert(predicate(value), 'Invalid argument value = ' + exports.stringify(value) + ' supplied to irreducible type ' + name); | ||
} | ||
@@ -278,23 +270,23 @@ | ||
var Str = irreducible('Str', isString); | ||
var Str = irreducible('String', isString); | ||
var Num = irreducible('Num', isNumber); | ||
var Num = irreducible('Number', isNumber); | ||
var Bool = irreducible('Bool', isBoolean); | ||
var Bool = irreducible('Boolean', isBoolean); | ||
var Arr = irreducible('Arr', isArray); | ||
var Arr = irreducible('Array', isArray); | ||
var Obj = irreducible('Obj', isObject); | ||
var Obj = irreducible('Object', isObject); | ||
var Func = irreducible('Func', isFunction); | ||
var Func = irreducible('Function', isFunction); | ||
var Err = irreducible('Err', function (x) { | ||
var Err = irreducible('Error', function (x) { | ||
return isInstanceOf(x, Error); | ||
}); | ||
var Re = irreducible('Re', function (x) { | ||
var Re = irreducible('RegExp', function (x) { | ||
return isInstanceOf(x, RegExp); | ||
}); | ||
var Dat = irreducible('Dat', function (x) { | ||
var Dat = irreducible('Date', function (x) { | ||
return isInstanceOf(x, Date); | ||
@@ -306,4 +298,4 @@ }); | ||
if (process.env.NODE_ENV !== 'production') { | ||
assert(dict(Str, Func).is(props), 'Invalid argument props = ' + stringify(props) + ' supplied to struct(props, name): expected a dictionary of types'); | ||
assert(isTypeName(name), 'Invalid argument name = ' + stringify(props) + ' supplied to struct(props, name): expected a string'); | ||
assert(dict(Str, Func).is(props), 'Invalid argument props = ' + exports.stringify(props) + ' supplied to struct(props, name): expected a dictionary of tcomb types'); | ||
assert(isTypeName(name), 'Invalid argument name = ' + exports.stringify(name) + ' supplied to struct(props, name): expected a string'); | ||
} | ||
@@ -324,3 +316,3 @@ | ||
if (process.env.NODE_ENV !== 'production') { | ||
assert(isObject(value), 'Invalid argument value = ' + stringify(value) + ' supplied to struct ' + displayName + ': expected an object'); | ||
assert(isObject(value), 'Invalid argument value = ' + exports.stringify(value) + ' supplied to struct ' + displayName + ': expected an object'); | ||
} | ||
@@ -368,3 +360,3 @@ | ||
if (process.env.NODE_ENV !== 'production') { | ||
assert(isStruct(x), 'Invalid argument structs[' + i + '] = ' + stringify(structs[i]) + ' supplied to ' + displayName + '.extend(structs, name)'); | ||
assert(isStruct(x), 'Invalid argument structs[' + i + '] = ' + exports.stringify(structs[i]) + ' supplied to ' + displayName + '.extend(structs, name)'); | ||
} | ||
@@ -385,4 +377,4 @@ return x.meta.props; | ||
if (process.env.NODE_ENV !== 'production') { | ||
assert(isArray(types) && types.every(isFunction) && types.length >= 2, 'Invalid argument types = ' + stringify(types) + ' supplied to union(types, name): expected an array of at least 2 types'); | ||
assert(isTypeName(name), 'Invalid argument name = ' + stringify(name) + ' supplied to union(types, name): expected a string'); | ||
assert(isArray(types) && types.every(isFunction) && types.length >= 2, 'Invalid argument types = ' + exports.stringify(types) + ' supplied to union(types, name): expected an array of at least 2 types'); | ||
assert(isTypeName(name), 'Invalid argument name = ' + exports.stringify(name) + ' supplied to union(types, name): expected a string'); | ||
} | ||
@@ -438,3 +430,3 @@ | ||
if (process.env.NODE_ENV !== 'production') { | ||
assert(isFunction(type), 'Invalid argument type = ' + stringify(type) + ' supplied to maybe(type, name): expected a type'); | ||
assert(isFunction(type), 'Invalid argument type = ' + exports.stringify(type) + ' supplied to maybe(type, name): expected a type'); | ||
} | ||
@@ -447,3 +439,3 @@ | ||
if (process.env.NODE_ENV !== 'production') { | ||
assert(isTypeName(name), 'Invalid argument name = ' + stringify(name) + ' supplied to maybe(type, name): expected a string'); | ||
assert(isTypeName(name), 'Invalid argument name = ' + exports.stringify(name) + ' supplied to maybe(type, name): expected a string'); | ||
} | ||
@@ -478,7 +470,7 @@ | ||
if (process.env.NODE_ENV !== 'production') { | ||
assert(isObject(map), 'Invalid argument map = ' + stringify(map) + ' supplied to enums(map, name): expected a hash of strings / numbers'); | ||
assert(isTypeName(name), 'Invalid argument name = ' + stringify(name) + ' supplied to enums(map, name): expected a string'); | ||
assert(isObject(map), 'Invalid argument map = ' + exports.stringify(map) + ' supplied to enums(map, name): expected a hash of strings / numbers'); | ||
assert(isTypeName(name), 'Invalid argument name = ' + exports.stringify(name) + ' supplied to enums(map, name): expected a string'); | ||
} | ||
var defaultName = Object.keys(map).map(function (k) { return JSON.stringify(k); }).join(' | '); | ||
var defaultName = Object.keys(map).map(function (k) { return exports.stringify(k); }).join(' | '); | ||
@@ -490,3 +482,3 @@ var displayName = name || defaultName; | ||
forbidNewOperator(this, Enums); | ||
assert(Enums.is(value), 'Invalid argument value = ' + stringify(value) + ' supplied to enums ' + displayName + ': expected one of ' + stringify(Object.keys(map))); | ||
assert(Enums.is(value), 'Invalid argument value = ' + exports.stringify(value) + ' supplied to enums ' + displayName + ': expected one of ' + exports.stringify(Object.keys(map))); | ||
} | ||
@@ -523,4 +515,4 @@ return value; | ||
if (process.env.NODE_ENV !== 'production') { | ||
assert(isArray(types) && types.every(isFunction), 'Invalid argument types = ' + stringify(types) + ' supplied to tuple(types, name): expected an array of types'); | ||
assert(isTypeName(name), 'Invalid argument name = ' + stringify(name) + ' supplied to tuple(types, name): expected a string'); | ||
assert(isArray(types) && types.every(isFunction), 'Invalid argument types = ' + exports.stringify(types) + ' supplied to tuple(types, name): expected an array of types'); | ||
assert(isTypeName(name), 'Invalid argument name = ' + exports.stringify(name) + ' supplied to tuple(types, name): expected a string'); | ||
} | ||
@@ -541,3 +533,3 @@ | ||
if (process.env.NODE_ENV !== 'production') { | ||
assert(isArray(value) && value.length === types.length, 'Invalid argument value = ' + stringify(value) + ' supplied to tuple ' + displayName + ': expected an array of length ' + types.length); | ||
assert(isArray(value) && value.length === types.length, 'Invalid argument value = ' + exports.stringify(value) + ' supplied to tuple ' + displayName + ': expected an array of length ' + types.length); | ||
} | ||
@@ -591,5 +583,5 @@ | ||
if (process.env.NODE_ENV !== 'production') { | ||
assert(isFunction(type), 'Invalid argument type = ' + stringify(type) + ' supplied to subtype(type, predicate, name): expected a type'); | ||
assert(isFunction(type), 'Invalid argument type = ' + exports.stringify(type) + ' supplied to subtype(type, predicate, name): expected a type'); | ||
assert(isFunction(predicate), 'Invalid argument predicate supplied to subtype(type, predicate, name): expected a function'); | ||
assert(isTypeName(name), 'Invalid argument name = ' + stringify(name) + ' supplied to subtype(type, predicate, name): expected a string'); | ||
assert(isTypeName(name), 'Invalid argument name = ' + exports.stringify(name) + ' supplied to subtype(type, predicate, name): expected a string'); | ||
} | ||
@@ -610,3 +602,3 @@ | ||
if (process.env.NODE_ENV !== 'production') { | ||
assert(predicate(x), 'Invalid argument value = ' + stringify(value) + ' supplied to subtype ' + displayName); | ||
assert(predicate(x), 'Invalid argument value = ' + exports.stringify(value) + ' supplied to subtype ' + displayName); | ||
} | ||
@@ -640,4 +632,4 @@ | ||
if (process.env.NODE_ENV !== 'production') { | ||
assert(isFunction(type), 'Invalid argument type = ' + stringify(type) + ' supplied to list(type, name): expected a type'); | ||
assert(isTypeName(name), 'Invalid argument name = ' + stringify(name) + ' supplied to list(type, name): expected a string'); | ||
assert(isFunction(type), 'Invalid argument type = ' + exports.stringify(type) + ' supplied to list(type, name): expected a type'); | ||
assert(isTypeName(name), 'Invalid argument name = ' + exports.stringify(name) + ' supplied to list(type, name): expected a string'); | ||
} | ||
@@ -658,3 +650,3 @@ | ||
if (process.env.NODE_ENV !== 'production') { | ||
assert(isArray(value), 'Invalid argument value = ' + stringify(value) + ' supplied to list ' + displayName); | ||
assert(isArray(value), 'Invalid argument value = ' + exports.stringify(value) + ' supplied to list ' + displayName); | ||
} | ||
@@ -703,5 +695,5 @@ | ||
if (process.env.NODE_ENV !== 'production') { | ||
assert(isFunction(domain), 'Invalid argument domain = ' + stringify(domain) + ' supplied to dict(domain, codomain, name): expected a type'); | ||
assert(isFunction(codomain), 'Invalid argument codomain = ' + stringify(codomain) + ' supplied to dict(domain, codomain, name): expected a type'); | ||
assert(isTypeName(name), 'Invalid argument name = ' + stringify(name) + ' supplied to dict(domain, codomain, name): expected a string'); | ||
assert(isFunction(domain), 'Invalid argument domain = ' + exports.stringify(domain) + ' supplied to dict(domain, codomain, name): expected a type'); | ||
assert(isFunction(codomain), 'Invalid argument codomain = ' + exports.stringify(codomain) + ' supplied to dict(domain, codomain, name): expected a type'); | ||
assert(isTypeName(name), 'Invalid argument name = ' + exports.stringify(name) + ' supplied to dict(domain, codomain, name): expected a string'); | ||
} | ||
@@ -727,3 +719,3 @@ | ||
if (process.env.NODE_ENV !== 'production') { | ||
assert(isObject(value), 'Invalid argument value = ' + stringify(value) + ' supplied to dict ' + displayName); | ||
assert(isObject(value), 'Invalid argument value = ' + exports.stringify(value) + ' supplied to dict ' + displayName); | ||
} | ||
@@ -783,5 +775,5 @@ | ||
if (process.env.NODE_ENV !== 'production') { | ||
assert(list(Func).is(domain), 'Invalid argument domain = ' + stringify(domain) + ' supplied to func(domain, codomain, name): expected an array of types'); | ||
assert(isFunction(codomain), 'Invalid argument codomain = ' + stringify(codomain) + ' supplied to func(domain, codomain, name): expected a type'); | ||
assert(isTypeName(name), 'Invalid argument name = ' + stringify(name) + ' supplied to func(domain, codomain, name): expected a string'); | ||
assert(list(Func).is(domain), 'Invalid argument domain = ' + exports.stringify(domain) + ' supplied to func(domain, codomain, name): expected an array of types'); | ||
assert(isFunction(codomain), 'Invalid argument codomain = ' + exports.stringify(codomain) + ' supplied to func(domain, codomain, name): expected a type'); | ||
assert(isTypeName(name), 'Invalid argument name = ' + exports.stringify(name) + ' supplied to func(domain, codomain, name): expected a string'); | ||
} | ||
@@ -800,3 +792,3 @@ | ||
if (process.env.NODE_ENV !== 'production') { | ||
assert(FuncType.is(value), 'Invalid argument value = ' + stringify(value) + ' supplied to func ' + displayName); | ||
assert(FuncType.is(value), 'Invalid argument value = ' + exports.stringify(value) + ' supplied to func ' + displayName); | ||
} | ||
@@ -829,3 +821,3 @@ | ||
assert(isFunction(f), 'Invalid argument f supplied to func.of ' + displayName + ': expected a function'); | ||
assert(isNil(curried) || isBoolean(curried), 'Invalid argument curried = ' + stringify(curried) + ' supplied to func.of ' + displayName + ': expected a boolean'); | ||
assert(isNil(curried) || isBoolean(curried), 'Invalid argument curried = ' + exports.stringify(curried) + ' supplied to func.of ' + displayName + ': expected a boolean'); | ||
} | ||
@@ -838,3 +830,3 @@ | ||
function fn() { | ||
var args = slice.call(arguments); | ||
var args = Array.prototype.slice.call(arguments); | ||
var len = curried ? | ||
@@ -875,3 +867,2 @@ args.length : | ||
mixin(exports, { | ||
stringify: stringify, | ||
is: is, | ||
@@ -886,10 +877,19 @@ isType: isType, | ||
Str: Str, | ||
String: Str, | ||
Num: Num, | ||
Number: Num, | ||
Bool: Bool, | ||
Boolean: Bool, | ||
Arr: Arr, | ||
Array: Arr, | ||
Obj: Obj, | ||
Object: Obj, | ||
Func: Func, | ||
Function: Func, | ||
Err: Err, | ||
Error: Err, | ||
Re: Re, | ||
RegExp: Re, | ||
Dat: Dat, | ||
Date: Dat, | ||
irreducible: irreducible, | ||
@@ -896,0 +896,0 @@ struct: struct, |
{ | ||
"name": "tcomb", | ||
"version": "2.0.1", | ||
"version": "2.1.0", | ||
"description": "Type checking and DDD for JavaScript", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
115
README.md
[![build status](https://img.shields.io/travis/gcanti/tcomb/master.svg?style=flat-square)](https://travis-ci.org/gcanti/tcomb) | ||
[![dependency status](https://img.shields.io/david/gcanti/tcomb.svg?style=flat-square)](https://david-dm.org/gcanti/tcomb) | ||
![npm downloads](https://img.shields.io/npm/dm/tcomb.svg) | ||
tcomb is a library for Node.js and the browser which allows you to **check the types** of JavaScript values at runtime with a simple syntax. It's great for **Domain Driven Design** and for adding safety to your internal code. | ||
tcomb is a library for Node.js and the browser which allows you to **check the types** of JavaScript values at runtime with a simple and concise syntax. It's great for **Domain Driven Design** and for adding safety to your internal code. | ||
# Features | ||
1. **immutability**: instances are immutables (using `Object.freeze`) in development | ||
2. **speed**: asserts are active only in development mode and stripped in production code. | ||
3. **DDD**: write complex domain models in a breeze and with a small code footprint | ||
4. **debugging**: you can customize the behaviour when an assert fails leveraging the power of Chrome DevTools | ||
5. **runtime type introspection**: every model written with tcomb is inspectable at runtime | ||
6. **JSON**: encodes/decodes domain models to/from JSON for free | ||
## Lightweight | ||
# Quick example | ||
3KB gzipped. | ||
## Domain Driven Design | ||
Write complex domain models in a breeze and with a small code footprint. Supported types: | ||
* user defined types | ||
* structs | ||
* lists | ||
* enums | ||
* subtypes | ||
* unions | ||
* the option type | ||
* tuples | ||
* dictionaries | ||
* functions | ||
## Based on set theory | ||
- [JavaScript, Types and Sets - Part I](https://gcanti.github.io/2014/09/29/javascript-types-and-sets.html) | ||
- [JavaScript, Types and Sets - Part II](https://gcanti.github.io/2014/10/07/javascript-types-and-sets-part-II.html) | ||
## Safety | ||
All models defined by tcomb are type checked (using a built-in `assert(guard, [message])` function). | ||
## Immutability and immutability helpers | ||
Instances are immutables by default using `Object.freeze`. This means you can use standard JavaScript objects and arrays. You don't have to change how you normally code. You can update an immutable instance with the provided `update` function: | ||
```js | ||
MyType.update(instance, spec) | ||
``` | ||
The following commands are compatible with the [Facebook Immutability Helpers](http://facebook.github.io/react/docs/update.html): | ||
* `$push` | ||
* `$unshift` | ||
* `$splice` | ||
* `$set` | ||
* `$apply` | ||
* `$merge` | ||
## Speed | ||
`Object.freeze` and the asserts are executed only during development and stripped out in production (using `process.env.NODE_ENV = 'production'` tests). | ||
## Debugging with Chrome DevTools | ||
You can customize the behaviour when an assert fails leveraging the power of Chrome DevTools. | ||
```js | ||
import t from 'tcomb'; | ||
// define a custom integer type | ||
const Integer = t.subtype(t.Num, n => n % 1 === 0); | ||
// default behaviour | ||
t.fail = function fail(message) { | ||
throw new TypeError('[tcomb] ' + message); // set "Pause on exceptions" on the "Sources" panel | ||
}; | ||
// .. or define your own handler | ||
t.fail = function fail(message) { | ||
debugger; // starts the Chrome DevTools debugger | ||
throw new TypeError('[tcomb] ' + message); | ||
}; | ||
``` | ||
## Runtime type introspection | ||
Every model is inspectable at runtime. You can read and reuse the informations stored in your types (in a `meta` object). See: | ||
- [tcomb-validation](https://github.com/gcanti/tcomb-validation) | ||
- [tcomb-form](https://github.com/gcanti/tcomb-form) | ||
- [JSON API Validation In Node.js](https://gcanti.github.io/2014/09/15/json-api-validation-in-node.html) | ||
## Easy JSON serialization / deseralization | ||
Encodes / decodes your domain models to / from JSON for free. See: | ||
- [JSON Deserialization Into An Object Model](https://gcanti.github.io/2014/09/12/json-deserialization-into-an-object-model.html) | ||
# Code example | ||
```js | ||
import t from 'tcomb'; | ||
// a user defined type | ||
const Integer = t.subtype(t.Number, (n) => n % 1 === 0); | ||
// a struct | ||
const Person = t.struct({ | ||
name: t.Str, // required string | ||
surname: t.maybe(t.Str), // optional string | ||
age: Integer, // required integer | ||
tags: t.list(t.Str) // a list of strings | ||
name: t.String, // required string | ||
surname: t.maybe(t.String), // optional string | ||
age: Integer, // required integer | ||
tags: t.list(t.String) // a list of strings | ||
}); | ||
// methods are defined as usual | ||
Person.prototype.getFullName = function () { | ||
return `${this.name} ${this.surname}`; | ||
}; | ||
// an instance of Person (the keyword new is optional) | ||
const person = new Person({ | ||
@@ -34,7 +117,7 @@ name: 'Giulio', | ||
age: 41, | ||
tags: ['developer', 'rock climber'] | ||
tags: ['js developer', 'rock climber'] | ||
}); | ||
``` | ||
# Documentation | ||
# Docs | ||
@@ -41,0 +124,0 @@ [GUIDE.md](GUIDE.md) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
46669
675
133