![New axobject-query Maintainer Faces Backlash Over Controversial Decision to Support Legacy Node.js Versions](https://cdn.sanity.io/images/cgdhsj6q/production/86e6ebdea652d20da070ebbda20134b839972db7-1024x1024.webp?w=800&fit=max&auto=format)
Security News
New axobject-query Maintainer Faces Backlash Over Controversial Decision to Support Legacy Node.js Versions
A JavaScript library maintainer is under fire after merging a controversial PR to support legacy versions of Node.js.
tcomb
Advanced tools
Package description
The tcomb npm package 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 is useful for enforcing type safety, defining domain models, and creating composable and reusable type checkers.
Type Checking
This feature allows you to define a structure with specific types and create instances that adhere to those types.
const t = require('tcomb');
const Person = t.struct({ name: t.String, age: t.Number });
const person = Person({ name: 'Giulio', age: 43 });
Function Argument Validation
This feature enables you to validate function arguments to ensure they are of the expected type.
const t = require('tcomb');
function sum(a, b) {
t.Number(a);
t.Number(b);
return a + b;
}
sum(1, 2);
Subtyping
This feature allows you to create subtypes based on existing types with additional constraints.
const t = require('tcomb');
const Positive = t.subtype(t.Number, n => n >= 0);
const positiveNumber = Positive(10);
Refinement
This feature is similar to subtyping but is specifically for refining types to a more specific subset.
const t = require('tcomb');
const Integer = t.refinement(t.Number, n => n % 1 === 0);
const integerNumber = Integer(42);
Enums
This feature allows you to define a set of constants and ensure values match one of those constants.
const t = require('tcomb');
const Role = t.enums({ Admin: 'Admin', User: 'User' });
const userRole = Role('User');
Prop-types is a library for React that is used to document the intended types of properties passed to components. It is similar to tcomb in that it provides runtime type checking, but it is specifically tailored for React's component props.
io-ts is a TypeScript runtime type system for IO decoding/encoding. It is similar to tcomb in providing runtime type checking and validation, but it leverages TypeScript's type system for added compile-time safety.
Joi is an object schema description language and validator for JavaScript objects. It provides a powerful and expressive way to define and validate data structures. It is similar to tcomb in terms of validation capabilities but has a different API and is often used for validating API input.
Ajv is a JSON schema validator. It validates data against JSON Schema standards and is similar to tcomb in terms of validation. However, it uses a JSON-based schema definition rather than a programmatic API.
Readme
"Si vis pacem, para bellum" (Vegetius 5th century)
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, for testing and for adding safety to your internal code.
tcomb is based on set theory.
What's a type? In tcomb a type is a function T
such that
T
has signature T(value, [mut])
where value
depends on the nature of T
and the optional boolean mut
makes the instance mutable (default false
)T
is idempotent: T(T(value, mut), mut) === T(value, mut)
T
owns a static function T.is(x)
returning true
if x
is an instance of T
Note: 2. implies that T
can be used as a default JSON decoder
The library provides a built-in assert
function, if an assert fails the debugger kicks in
so you can inspect the stack and quickly find out what's wrong.
You can handle:
JavaScript native types
null
and undefined
type combinators (build new types from those already defined)
Let's build a product model
var Product = struct({
name: Str, // required string
desc: maybe(Str), // optional string, can be null
home: Url, // a subtype of a string
shippings: list(Str), // a list of shipping methods
category: Category, // enum, one of [audio, video]
price: Price, // a price (dollars) OR in another currency
size: tuple([Num, Num]), // width x height
warranty: dict(Str, Num) // a dictionary country -> covered years
});
var Url = subtype(Str, function (s) {
return s.indexOf('http://') === 0;
});
var Category = enums.of('audio video');
var ForeignPrice = struct({ currency: Str, amount: Num });
var Price = union([Num, ForeignPrice]);
Price.dispatch = function (x) {
return Num.is(x) ? Num : ForeignPrice;
};
// JSON of a product
var json = {
name: 'iPod',
desc: 'Engineered for maximum funness.',
home: 'http://www.apple.com/ipod/',
shippings: ['Same Day', 'Next Businness Day'],
category: 'audio',
price: {currency: 'EUR', amount: 100},
size: [2.4, 4.1],
warranty: {
US: 2,
IT: 1
}
};
// get an immutable instance, `new` is optional
var ipod = Product(json);
You have existing code and you want to add safety
// your code: plain old JavaScript class
function Point (x, y) {
this.x = x;
this.y = y;
}
var p = new Point(1, 'a'); // silent error
in order to "tcombify" your code you can simply add some asserts
function Point (x, y) {
assert(Num.is(x));
assert(Num.is(y));
this.x = x;
this.y = y;
}
var p = new Point(1, 'a'); // => fail! debugger kicks in
Node
npm install tcomb
Browser
bower install tcomb
or download the tcomb.min.js
file.
This library uses a few ES5 methods, you can use es5-shim
, es5-sham
and json2
to support old browsers
Run mocha
or npm test
in the project root.
In production envs you don't want to leak failures to the user
// override onFail hook
options.onFail = function (message) {
try {
// capture stack trace
throw new Error(message);
} catch (e) {
// use you favourite JavaScript error logging service
console.log(e.stack);
}
};
assert(guard, [message], [values...]);
If guard !== true
the debugger kicks in.
guard
boolean conditionmessage
optional string useful for debugging, formatted with values like util.format in NodeExample
assert(1 === 2); // throws 'assert(): failed'
assert(1 === 2, 'error!'); // throws 'error!'
assert(1 === 2, 'error: %s !== %s', 1, 2); // throws 'error: 1 !== 2'
To customize failure behaviour, see options.onFail
.
struct(props, [name])
Defines a struct like type.
props
hash name -> typename
optional string useful for debuggingExample
"use strict";
// defines a struct with two numerical props
var Point = struct({
x: Num,
y: Num
});
// methods are defined as usual
Point.prototype.toString = function () {
return '(' + this.x + ', ' + this.y + ')';
};
// costructor usage, p is immutable
var p = Point({x: 1, y: 2});
p.x = 2; // => TypeError
p = Point({x: 1, y: 2}, true); // now p is mutable
p.x = 2; // ok
Returns true
if x
is an instance of the struct.
Point.is(p); // => true
Returns a new type with the additional specified props
var Point = struct({
x: Num,
y: Num
}, 'Point');
var Point3D = Point.extend({z: Num}, 'Point3D'); // composition, not inheritance
var p = new Point3D({x: 1, y: 2, z: 3});
// `props` can be an array of new props
var Point4D = Point.extend([{z: Num}, {time: Num}], 'Point4D');
union(types, [name])
Defines a union of types.
types
array of typesname
optional string useful for debuggingExample
var Circle = struct({
center: Point,
radius: Num
});
var Rectangle = struct({
bl: Point, // bottom left vertex
tr: Point // top right vertex
});
var Shape = union([
Circle,
Rectangle
]);
// you must implement the dispatch() function in order to use `Shape` as a contructor
Shape.dispatch = function (x) {
return x.hasOwnProperty('center') ? Circle : Rectangle;
};
var circle = Shape({center: {x: 1, y: 0}, radius: 10});
var rectangle = Shape({bl: {x: 0, y: 0}, tr: {x: 1, y: 1}});
Returns true
if x
belongs to the union.
Shape.is(new Circle({center: p, radius: 10})); // => true
maybe(type, [name])
Same as union([Nil, type])
.
// the value of a radio input where null = no selection
var Radio = maybe(Str);
Radio.is('a'); // => true
Radio.is(null); // => true
Radio.is(1); // => false
enums(map, [name])
Defines an enum of strings.
map
hash enum -> valuename
optional string useful for debuggingExample
var Direction = enums({
North: 'North',
East: 'East',
South: 'South',
West: 'West'
});
Returns true
if x
belongs to the enum.
Direction.is('North'); // => true
Returns an enums of an array of keys, useful when you don't mind to define custom values for the enums.
keys
array (or string) of keysname
optional string useful for debuggingExample
// result is the same as the main example
var Direction = enums.of(['North', 'East', 'South', 'West']);
// or..
Direction = enums.of('North East South West');
tuple(types, [name])
Defines a tuple whose coordinates have the specified types.
types
array of coordinates typesname
optional string useful for debuggingExample
var Area = tuple([Num, Num]);
// constructor usage, area is immutable
var area = Area([1, 2]);
0-tuples and 1-tuples are also supported
var Nothing = tuple([]);
var JustNum = tuple([Num]);
Returns true
if x
belongs to the tuple.
Area.is([1, 2]); // => true
Area.is([1, 'a']); // => false, the second element is not a Num
Area.is([1, 2, 3]); // => false, too many elements
subtype(type, predicate, [name])
Defines a subtype of an existing type.
type
the supertypepredicate
a function with signature (x) -> boolean
name
optional string useful for debuggingExample
// points of the first quadrant
var Q1Point = subtype(Point, function (p) {
return p.x >= 0 && p.y >= 0;
});
// costructor usage, p is immutable
var p = Q1Point({x: 1, y: 2});
p = Q1Point({x: -1, y: -2}); // => fail!
Note. You can't add methods to Q1Point
prototype
, add them to the supertype prototype
if needed.
Returns true
if x
belongs to the subtype.
var Int = subtype(Num, function (n) {
return n === parseInt(n, 10);
});
Int.is(2); // => true
Int.is(1.1); // => false
list(type, [name])
Defines an array where all the elements are of type T
.
type
type of all the elementsname
optional string useful for debuggingExample
var Path = list(Point);
// costructor usage, path is immutable
var path = Path([
{x: 0, y: 0},
{x: 1, y: 1}
]);
Returns true
if x
belongs to the list.
var p1 = Point({x: 0, y: 0});
var p2 = Point({x: 1, y: 2});
Path.is([p1, p2]); // => true
dict(domain, codomain, [name])
Defines a dictionary domain -> codomain.
domain
the type of the keyscodomain
the type of the valuesname
optional string useful for debuggingExample
// defines a dictionary of numbers
var Tel = dict(Str, Num);
Returns true
if x
is an instance of the dict.
Tel.is({'jack': 4098, 'sape': 4139}); // => true
Type.update(instance, spec)
The following commands are compatible with the Facebook Immutability Helpers.
{$remove: keys}
var Type = dict(Str, Num);
var instance = Type({a: 1, b: 2});
var updated = Type.update(instance, {$remove: ['a']}); // => {b: 2}
{$swap: {from: number, to: number}}
var Type = list(Num);
var instance = Type([1, 2, 3, 4]);
var updated = Type.update(instance, {'$swap': {from: 1, to: 2}}); // => [1, 3, 2, 4]
You can add your custom commands updating the util.update.commands
hash.
Typed functions may be defined like this:
// add takes two `Num`s and returns a `Num`
var add = func([Num, Num], Num)
.of(function (x, y) { return x + y; });
And used like this:
add("Hello", 2); // Raises error: Invalid `Hello` supplied to `Num`
add("Hello"); // Raises error: Invalid `Hello` supplied to `Num`
add(1, 2); // Returns: 3
add(1)(2); // Returns: 3
func(Domain, Codomain, name)
Returns a function type whose functions have their domain and codomain specified and constrained.
Domain
: the type of the function's argument (or list
of types of the function's arguments)Codomain
: the type of the function's return valuename
: optional string useful for debuggingfunc
can be used to define function types using native types:
// An `A` takes a `Str` and returns an `Num`
var A = func(Str, Num);
The domain and codomain can also be specified using types from any combinator including func
:
// A `B` takes a `Func` (which takes a `Str` and returns a `Num`) and returns a `Str`.
var B = func(func(Str, Num), Str);
// An `ExcitedStr` is a `Str` containing an exclamation mark
var ExcitedStr = subtype(Str, function (s) { return s.indexOf('!') !== -1; }, 'ExcitedStr');
// An `Exciter` takes a `Str` and returns an `ExcitedStr`
var Exciter = func(Str, ExcitedStr);
Additionally the domain can be expressed as a list
of types:
// A `C` takes an `A`, a `B` and a `Str` and returns a `Num`
var C = func([A, B, Str], Num);
func(A, B).of(f);
Returns a function where the domain and codomain are typechecked against the function type.
If the function is passed values which are outside of the domain or returns values which are outside of the codomain it will raise an error:
var simpleQuestionator = Exciter.of(function (s) { return s + '?'; });
var simpleExciter = Exciter.of(function (s) { return s + '!'; });
// Raises error:
// Invalid `Hello?` supplied to `ExcitedStr`, insert a valid value for the subtype
simpleQuestionator('Hello');
// Raises error: Invalid `1` supplied to `Str`
simpleExciter(1);
// Returns: 'Hello!'
simpleExciter('Hello');
The returned function may also be partially applied:
// We can reasonably suggest that add has the following type signature
// add : Num -> Num -> Num
var add = func([Num, Num], Num)
.of(function (x, y) { return x + y });
var addHello = add("Hello"); // As this raises: "Error: Invalid `Hello` supplied to `Num`"
var add2 = add(2);
add2(1); // And this returns: 3
func(A, B).is(x);
Returns true if x belongs to the type.
Exciter.is(simpleExciter); // Returns: true
Exciter.is(simpleQuestionator); // Returns: true
var id = function (x) { return x; };
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
I added a tcomb.sjs
file containing some sweet.js macros, here some examples:
// structs
type Point struct {
x: Num,
y: Num
}
// unions
type Shape union {
Circle,
Rectangle
}
// tuples
type Coords tuple {
Num,
Num
}
// enums
type Direction enums {
'North',
'East',
'South',
'West'
}
// enums with specified values
type Direction enums {
'North': 0,
'East': 1,
'South': 2,
'West': 3
}
// subtypes
type Positive subtype<Num> n {
return n > 0;
}
// irriducibles types, like JavaScript primitives
type Irriducible irriducible x {
return typeof x === 'function';
}
// maybe
type Maybe maybe<Str>
// lists
type List list<Str>
// dictionaries
type Dict dict<Str>
// functions
fn add (x: Num, y: Num) {
return x + y;
}
// functions with checked return value
fn add (x: Num, y: Num) -> Num {
return x + y;
}
The MIT License (MIT)
FAQs
Type checking and DDD for JavaScript
The npm package tcomb receives a total of 833,516 weekly downloads. As such, tcomb popularity was classified as popular.
We found that tcomb demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
A JavaScript library maintainer is under fire after merging a controversial PR to support legacy versions of Node.js.
Security News
Results from the 2023 State of JavaScript Survey highlight key trends, including Vite's dominance, rising TypeScript adoption, and the enduring popularity of React. Discover more insights on developer preferences and technology usage.
Security News
The US Justice Department has penalized two consulting firms $11.3 million for failing to meet cybersecurity requirements on federally funded projects, emphasizing strict enforcement to protect sensitive government data.