Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/phadej/typify
Runtime type checking for JavaScript
https://github.com/phadej/typify
Last synced: 11 days ago
JSON representation
Runtime type checking for JavaScript
- Host: GitHub
- URL: https://github.com/phadej/typify
- Owner: phadej
- License: bsd-3-clause
- Created: 2013-07-22T07:58:58.000Z (over 11 years ago)
- Default Branch: master
- Last Pushed: 2019-03-04T12:20:31.000Z (over 5 years ago)
- Last Synced: 2024-10-11T23:53:19.479Z (26 days ago)
- Language: JavaScript
- Size: 230 KB
- Stars: 76
- Watchers: 3
- Forks: 7
- Open Issues: 5
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# typify
> Runtime type-checking.
[![Build Status](https://secure.travis-ci.org/phadej/typify.svg?branch=master)](http://travis-ci.org/phadej/typify)
[![NPM version](https://badge.fury.io/js/typify.svg)](http://badge.fury.io/js/typify)
[![Dependency Status](https://gemnasium.com/phadej/typify.svg)](https://gemnasium.com/phadej/typify)
[![Code Climate](https://img.shields.io/codeclimate/github/phadej/typify.svg)](https://codeclimate.com/github/phadej/typify)## Getting Started
Install the module with: `npm install typify`
## Synopsis
```javascript
// Browser
//// Node
var typify = require("typify");/*
* `sum` function takes either two numbers or two strings as a parameter,
* and returns a number or a string respectively.
*/
var sum = typify("sum :: a : number|string => a -> a -> a", function (a, b) {
return a + b;
});/*
* `toArray` function takes either an array of numbers or a single number,
* and returns an array of numbers.
*
* We could write a more general, polymorphic function with type signature
* `toArray :: a : *, (array a)|a -> array a`, where `*` means _any type_.
*
* Unfortunately any type `*` is seriously any.
* Types as *typify* understands them, are more like Java's interfaces or Haskell's typeclasses.
* Of course, we can iterate through them all, but we cannot deduce the most principal type (because it doesn't exist).
* So eg. function signature `id :: a : *, a -> a` behaves similarly to `id :: * -> *`, which isn't strict enough.
*/
var toNumberArray = typify("toNumberArray :: (array number)|number -> array number", function (a) {
return Array.isArray(a) ? a : [a];
});/*
* `myParseInt` takes a string and an optional number (radix) and returns a number.
*/
var myParseInt = typify("myParseInt :: string -> number? -> number", function (n, radix) {
return parseInt(n, radix || 10)
});/*
* `foo` takes at least one number parameter and returns a number.
*/
var foo = typify("foo :: number -> number.. -> number", function (a) {
return a + arguments.length;
});
```## Documentation
### API
- `typify(functionSpec, fun)` - decorate function with run-time type check
- `typify.create()` - create new typify environment
- `typify.type(typename, checkFun)` - add new type with user-supplied existence check
- `typify.record(typename, recordspec)` - add new record type
- `typify.alias(typename, typespec)` - give name to the compound type
- `typify.mutual(typespecs)` - define multiple (possibly mutually recursive) types at once
- `typify.instance(name, cls)` - add new instance type
- `typify.check(typename, value) -> bool` - check membership of value in the type. `check` is [autoCurried](http://fitzgen.github.io/wu.js/#wu-autocurry)### Checkable type
*Checkable* means, that given an object you can check whether an object is or isn't of the particular type.
For example `number` is checkable type, given any object you can tell if it's a number.```javascript
typify.check('number', 1); // => true
typify.check('number', 'foobar'); // => false
```You could use `typify.assert` for type assertions:
```javascript
typify.check('number', 'foo'); // will throw `TypeError` exception
```There are few predefined checkable types:
- `number`
- `integer`
- `nat`: non-negative integer
- `positive` _x_
- `nonnegative` _x_
- `finite` _x_
- `string`
- `boolean`
- `date`
- `regexp`
- `function`, `fn`
- `array` _a_
- `map` _a_
- `tuple` _a_ _b_...
- `null`, `undefined`, `infinity`, `ninfinity`, `nan`, `true` and `false`#### Formal syntax of checkable type declaration:
- *checkable type* σ ::= σ_or
- σ_or ::= σ_and (`|` σ_and)*
- σ_and ::= σ_poly (`&` σ_poly)*
- σ_poly ::= *typename* σ_opt+ | σ_opt
- σ_opt = σ_term | σ_term `?`
- σ_record ::= `{` `}` | `{` σ_pair (`,` σ_pair)* `}`
- σ_pair ::= *identifier* `:` σ_term
- σ_term ::= `*` | α | *literal* | *typename* | `(` σ_alt `)`
- *type variable* α ::= *identifier*
- *literal* ::= /\d+/ | /"[^"]*"/ | /'[^']*'/ | true | false | null | undefined | nan | infinity | ninfinity
- *identifier*, *typename* ::= /[a-zA-Z_][a-zA-Z0-9_]*/### Function type
Function types are difficult to check. Given a function object, only you can tell, it's a function object.
To be more precise, you can decorate your function with *function type* signature to verify parameters' and result's types, but the check will occur only when function is executed ie. run-time.```javascript
var add = typify("add :: number -> number -> number", function (a, b) {
return a + b;
});console.log(add(1, 2)); // ok
console.log(add("foo", "bar")); // throws TypeError
```#### Formal syntax of function type declaration:
- *function type* λ ::= ν μ | ν Γ (σ `->`)* ρ σ
- *action* μ ::= `->` τ
- *context* Γ ::= α `:` Σ (`,` α `:` Σ)* `=>` | ε
- *typeset* Σ ::= σ_poly (`|` σ_poly)*
- *rest parameters* ρ ::= σ `...` `->` | `...` `->` | ε
- *function name* ν ::= *identifier* `::` | ε### New types
New types can be added with `typify.type` method:
```javascript
typify.type("char", function(n) {
return typeof n === "string" && n.length === 1;
});
```*Note:* opaque type checks should return `true`,
other *truthy* values will be considered errorneous in later versions.You can give names to (recursive) compound types with `typify.alias`:
```javascript
typify.alias("numstr", "number|string"); // numbers or strings
typify.alias("rarray", "array rarray"); // arrays of itself, eg [[[[[[]]]]]
```For mutually recursive types use `typify.mutual`:
```javascript
typify.mutual({
"foo": "list bar",
"bar": "list foo",
});
```Also you can define *record* types with `typify.record`:
```javascript
typify.record("person", {
name: "string",
age: "number",
});
```Record types may be recursive:
```javascript
typ.record("bst", {
left: "bst?",
right: "bst?",
});
```If you prefer `instanceof`, there is `typify.instance` helper in place:
```javascript
function Foo() {}
typ.instance("Foo", Foo);
typ.check("Foo", new Foo());
```### Hygiene usage
If you don't want to use global type database, you can create your own instance of *typify*:
```js
// In browser
var myTypify = typify.create();// or alternatively, using "let-binding":
(function (typify) {
// use typify as it would be global
}(typify.create()));// In node
var typify = require("typify").create();
```## Contributing
In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using `npm test` command.
## Release History
- 0.2.9 Closed records
- `typify.record(name, def, closed)`
- 0.2.8
- Change `date` and `regexp` checks to work in multiframe environments [#34](https://github.com/phadej/typify/issues/34)
- Fix typo in README.md [#35](https://github.com/phadej/typify/issues/35)
- Update dependencies
- 0.2.7
- Use make
- 0.2.6
- Updated dependencies
- 0.2.5
- `typify.assert`
- Added note about opaque type checks (`typify.type`)
- 0.2.4
- `arguments` built-in type
- `any` built-in type. Like `*` but not optional
- typified most of functions
- 0.2.3
- `fn` shorthand for the function type
- `typify.wrap` to typify modules
- [istanbul](http://gotwarlost.github.io/istanbul/) code covarage as part of the test suite
- `typify.adt` helper for specifying abstract data types -like structures
- `infinity`, `ninfinity` and `nan` literals
- unified implementation of `typify.type`, `typify.alias` and `typify.record`.
- The latter two will be deprecated in 0.3.0 and removed in 0.4.0
- 0.2.2
- mutually recursive types
- instanceof types
- 0.2.1
- anonymous record types
- tuple, numeric types
- mocha test-suite
- major code refactor
- 0.2.0
- Recursive record types
- Recursive aliases
- Intersection types
- Hygiene type environments- 0.1.1
- Record type
- Fixed typos in README.md- 0.1.0 Initial release
## License
Copyright (c) 2013 Oleg Grenrus. Licensed under the BSD3 license.
## Related work
### Javascript
- [rho-contracts](https://github.com/sefaira/rho-contracts.js)
- [ducktype](https://github.com/josdejong/ducktype)
- [type-check](https://github.com/gkz/type-check)### Others
- [Racket - Contracts for higher-order functions](http://dl.acm.org/citation.cfm?id=581484)
- [Typed Clojure](https://github.com/clojure/core.typed)
- [The Ruby Type Checker](http://www.cs.umd.edu/~jfoster/papers/oops13.pdf)### Gradual typing (of existing languages)
- [TypeScript](http://www.typescriptlang.org/)
- [hack](http://hacklang.org/)
- [Gradual typing on Wikipedia](http://en.wikipedia.org/wiki/Gradual_typing)