{"id":16338960,"url":"https://github.com/phadej/typify","last_synced_at":"2025-03-16T14:31:24.405Z","repository":{"id":9642504,"uuid":"11575832","full_name":"phadej/typify","owner":"phadej","description":"Runtime type checking for JavaScript","archived":false,"fork":false,"pushed_at":"2019-03-04T12:20:31.000Z","size":236,"stargazers_count":76,"open_issues_count":5,"forks_count":7,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-02-27T11:01:18.076Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/phadej.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-07-22T07:58:58.000Z","updated_at":"2024-02-08T19:43:30.000Z","dependencies_parsed_at":"2022-08-30T20:01:01.897Z","dependency_job_id":null,"html_url":"https://github.com/phadej/typify","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phadej%2Ftypify","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phadej%2Ftypify/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phadej%2Ftypify/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phadej%2Ftypify/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/phadej","download_url":"https://codeload.github.com/phadej/typify/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243819062,"owners_count":20352812,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-10T23:53:10.037Z","updated_at":"2025-03-16T14:31:23.959Z","avatar_url":"https://github.com/phadej.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# typify\n\n\u003e Runtime type-checking.\n\n[![Build Status](https://secure.travis-ci.org/phadej/typify.svg?branch=master)](http://travis-ci.org/phadej/typify)\n[![NPM version](https://badge.fury.io/js/typify.svg)](http://badge.fury.io/js/typify)\n[![Dependency Status](https://gemnasium.com/phadej/typify.svg)](https://gemnasium.com/phadej/typify)\n[![Code Climate](https://img.shields.io/codeclimate/github/phadej/typify.svg)](https://codeclimate.com/github/phadej/typify)\n\n## Getting Started\n\nInstall the module with: `npm install typify`\n\n## Synopsis\n\n```javascript\n// Browser\n// \u003cscript src=\"dist/typify.standalone.js\" type=\"text/javascript\"\u003e\u003c/script\u003e\n\n// Node\nvar typify = require(\"typify\");\n\n/*\n * `sum` function takes either two numbers or two strings as a parameter,\n * and returns a number or a string respectively.\n */\nvar sum = typify(\"sum :: a : number|string =\u003e a -\u003e a -\u003e a\", function (a, b) {\n    return a + b;\n});\n\n/*\n * `toArray` function takes either an array of numbers or a single number,\n * and returns an array of numbers.\n *\n * We could write a more general, polymorphic function with type signature\n * `toArray :: a : *, (array a)|a -\u003e array a`, where `*` means _any type_.\n *\n * Unfortunately any type `*` is seriously any.\n * Types as *typify* understands them, are more like Java's interfaces or Haskell's typeclasses.\n * Of course, we can iterate through them all, but we cannot deduce the most principal type (because it doesn't exist).\n * So eg. function signature `id :: a : *, a -\u003e a` behaves similarly to `id :: * -\u003e *`, which isn't strict enough.\n */\nvar toNumberArray = typify(\"toNumberArray :: (array number)|number -\u003e array number\", function (a) {\n    return Array.isArray(a) ? a : [a];\n});\n\n/*\n * `myParseInt` takes a string and an optional number (radix) and returns a number.\n */\nvar myParseInt = typify(\"myParseInt :: string -\u003e number? -\u003e number\", function (n, radix) {\n    return parseInt(n, radix || 10)\n});\n\n/*\n * `foo` takes at least one number parameter and returns a number.\n */\nvar foo = typify(\"foo :: number -\u003e number.. -\u003e number\", function (a) {\n    return a + arguments.length;\n});\n```\n\n## Documentation\n\n### API\n\n- `typify(functionSpec, fun)` - decorate function with run-time type check\n- `typify.create()` - create new typify environment\n- `typify.type(typename, checkFun)` - add new type with user-supplied existence check\n- `typify.record(typename, recordspec)` - add new record type\n- `typify.alias(typename, typespec)` - give name to the compound type\n- `typify.mutual(typespecs)` - define multiple (possibly mutually recursive) types at once\n- `typify.instance(name, cls)` - add new instance type\n- `typify.check(typename, value) -\u003e bool` - check membership of value in the type. `check` is [autoCurried](http://fitzgen.github.io/wu.js/#wu-autocurry)\n\n### Checkable type\n\n*Checkable* means, that given an object you can check whether an object is or isn't of the particular type.\nFor example `number` is checkable type, given any object you can tell if it's a number.\n\n```javascript\ntypify.check('number', 1); // =\u003e true\ntypify.check('number', 'foobar'); // =\u003e false\n```\n\nYou could use `typify.assert` for type assertions:\n\n```javascript\ntypify.check('number', 'foo'); // will throw `TypeError` exception\n```\n\n\nThere are few predefined checkable types:\n\n- `number`\n- `integer`\n- `nat`: non-negative integer\n- `positive` _x_\n- `nonnegative` _x_\n- `finite` _x_\n- `string`\n- `boolean`\n- `date`\n- `regexp`\n- `function`, `fn`\n- `array` _a_\n- `map` _a_\n- `tuple` _a_ _b_...\n- `null`, `undefined`, `infinity`, `ninfinity`, `nan`, `true` and `false`\n\n#### Formal syntax of checkable type declaration:\n\n- *checkable type* σ ::= σ_or\n    - σ_or ::= σ_and (`|` σ_and)*\n    - σ_and ::= σ_poly (`\u0026` σ_poly)*\n    - σ_poly ::= *typename* σ_opt+ | σ_opt\n    - σ_opt = σ_term | σ_term `?`\n    - σ_record ::= `{` `}` | `{` σ_pair (`,` σ_pair)* `}`\n    - σ_pair ::= *identifier* `:` σ_term\n    - σ_term ::= `*` | α | *literal* | *typename* | `(` σ_alt `)`\n- *type variable* α ::= *identifier*\n- *literal* ::= /\\d+/ | /\"[^\"]*\"/ | /'[^']*'/ | true | false | null | undefined | nan | infinity | ninfinity\n- *identifier*, *typename* ::= /[a-zA-Z_][a-zA-Z0-9_]*/\n\n### Function type\n\nFunction types are difficult to check. Given a function object, only you can tell, it's a function object.\nTo 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.\n\n```javascript\nvar add = typify(\"add :: number -\u003e number -\u003e number\", function (a, b) {\n    return a + b;\n});\n\nconsole.log(add(1, 2)); // ok\nconsole.log(add(\"foo\", \"bar\")); // throws TypeError\n```\n\n#### Formal syntax of function type declaration:\n\n- *function type* λ ::= ν μ | ν Γ (σ `-\u003e`)* ρ σ\n- *action* μ ::= `-\u003e` τ\n- *context* Γ ::= α `:` Σ (`,` α `:` Σ)* `=\u003e` | ε\n- *typeset* Σ ::= σ_poly (`|` σ_poly)*\n- *rest parameters* ρ ::= σ `...` `-\u003e` | `...` `-\u003e` | ε\n- *function name* ν ::= *identifier* `::` | ε\n\n### New types\n\nNew types can be added with `typify.type` method:\n\n```javascript\ntypify.type(\"char\", function(n) {\n    return typeof n === \"string\" \u0026\u0026 n.length === 1;\n});\n```\n\n*Note:* opaque type checks should return `true`,\nother *truthy* values will be considered errorneous in later versions.\n\nYou can give names to (recursive) compound types with `typify.alias`:\n```javascript\ntypify.alias(\"numstr\", \"number|string\"); // numbers or strings\ntypify.alias(\"rarray\", \"array rarray\"); // arrays of itself, eg [[[[[[]]]]]\n```\n\nFor mutually recursive types use `typify.mutual`:\n```javascript\ntypify.mutual({\n    \"foo\": \"list bar\",\n    \"bar\": \"list foo\",\n});\n```\n\nAlso you can define *record* types with `typify.record`:\n\n```javascript\ntypify.record(\"person\", {\n    name: \"string\",\n    age: \"number\",\n});\n```\n\nRecord types may be recursive:\n\n```javascript\ntyp.record(\"bst\", {\n    left: \"bst?\",\n    right: \"bst?\",\n});\n```\n\nIf you prefer `instanceof`, there is `typify.instance` helper in place:\n```javascript\nfunction Foo() {}\ntyp.instance(\"Foo\", Foo);\ntyp.check(\"Foo\", new Foo());\n```\n\n### Hygiene usage\n\nIf you don't want to use global type database, you can create your own instance of *typify*:\n\n```js\n// In browser\nvar myTypify = typify.create();\n\n// or alternatively, using \"let-binding\":\n(function (typify) {\n    // use typify as it would be global\n}(typify.create()));\n\n// In node\nvar typify = require(\"typify\").create();\n```\n\n## Contributing\n\nIn 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.\n\n## Release History\n\n- 0.2.9 Closed records\n    - `typify.record(name, def, closed)`\n- 0.2.8\n    - Change `date` and `regexp` checks to work in multiframe environments [#34](https://github.com/phadej/typify/issues/34)\n    - Fix typo in README.md [#35](https://github.com/phadej/typify/issues/35)\n    - Update dependencies\n- 0.2.7\n    - Use make\n- 0.2.6\n    - Updated dependencies\n- 0.2.5\n    - `typify.assert`\n    - Added note about opaque type checks (`typify.type`)\n- 0.2.4\n    - `arguments` built-in type\n    - `any` built-in type. Like `*` but not optional\n    - typified most of functions\n- 0.2.3\n    - `fn` shorthand for the function type\n    - `typify.wrap` to typify modules\n    - [istanbul](http://gotwarlost.github.io/istanbul/) code covarage as part of the test suite\n    - `typify.adt` helper for specifying abstract data types -like structures\n    - `infinity`, `ninfinity` and `nan` literals\n    - unified implementation of `typify.type`, `typify.alias` and `typify.record`.\n         - The latter two will be deprecated in 0.3.0 and removed in 0.4.0\n- 0.2.2\n    - mutually recursive types\n    - instanceof types\n- 0.2.1\n    - anonymous record types\n    - tuple, numeric types\n    - mocha test-suite\n    - major code refactor\n- 0.2.0\n    - Recursive record types\n    - Recursive aliases\n    - Intersection types\n    - Hygiene type environments\n\n- 0.1.1\n    - Record type\n    - Fixed typos in README.md\n\n- 0.1.0 Initial release\n\n## License\n\nCopyright (c) 2013 Oleg Grenrus. Licensed under the BSD3 license.\n\n## Related work\n\n### Javascript\n\n- [rho-contracts](https://github.com/sefaira/rho-contracts.js)\n- [ducktype](https://github.com/josdejong/ducktype)\n- [type-check](https://github.com/gkz/type-check)\n\n### Others\n\n- [Racket - Contracts for higher-order functions](http://dl.acm.org/citation.cfm?id=581484)\n- [Typed Clojure](https://github.com/clojure/core.typed)\n- [The Ruby Type Checker](http://www.cs.umd.edu/~jfoster/papers/oops13.pdf)\n\n### Gradual typing (of existing languages)\n\n- [TypeScript](http://www.typescriptlang.org/)\n- [hack](http://hacklang.org/)\n- [Gradual typing on Wikipedia](http://en.wikipedia.org/wiki/Gradual_typing)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphadej%2Ftypify","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fphadej%2Ftypify","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphadej%2Ftypify/lists"}