{"id":19434509,"url":"https://github.com/mlin/node-assert-type","last_synced_at":"2025-10-26T15:38:04.141Z","repository":{"id":6881485,"uuid":"8130769","full_name":"mlin/node-assert-type","owner":"mlin","description":"Concise runtime type assertions for Node.js","archived":false,"fork":false,"pushed_at":"2013-02-16T05:25:59.000Z","size":116,"stargazers_count":9,"open_issues_count":2,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-03T10:37:59.915Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"CoffeeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mlin.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-02-11T01:18:16.000Z","updated_at":"2024-06-02T03:18:57.000Z","dependencies_parsed_at":"2022-09-13T18:00:56.516Z","dependency_job_id":null,"html_url":"https://github.com/mlin/node-assert-type","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mlin%2Fnode-assert-type","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mlin%2Fnode-assert-type/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mlin%2Fnode-assert-type/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mlin%2Fnode-assert-type/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mlin","download_url":"https://codeload.github.com/mlin/node-assert-type/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250704833,"owners_count":21473769,"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-11-10T14:46:38.291Z","updated_at":"2025-10-26T15:38:04.086Z","avatar_url":"https://github.com/mlin.png","language":"CoffeeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# node-assert-type\n\n```\nnpm install assert-type\n```\n\n[![Build Status](https://travis-ci.org/mlin/node-assert-type.png)](https://travis-ci.org/mlin/node-assert-type)\n\nOne occasionally needs to design some JavaScript code conservatively, favoring\ncorrectness and safety over the language's natural strengths of flexibility\nand agility. Given JavaScript's dynamic typing, extensive runtime type\nassertions are a common product of such a [conservative\nmindset](https://plus.google.com/110981030061712822816/posts/KaSKeg4vQtz).\nThis node.js library makes it easier to write such assertions concisely. In\naddition to simple *identifier*-is-a-*type* assertions, it provides ways to\nalgebraically compose those into more complex assertions about objects,\narrays, and function signatures. A few examples may help illustrate:\n\n```\nvar ty = require(\"assert-type\");\nvar T = ty.Assert;\n\nfunction deorbitBurn(power,seconds) {\n  T(ty.num.finite)(power);   // assert power is a finite number (not NaN)\n  T(ty.int.nonneg)(seconds); // assert seconds is a nonnegative integer\n\n  // a more concise way to make the same two assertions:\n  T(ty.num.finite, ty.int.nonneg)(power, seconds);\n\n  ...\n}\n\nfunction chooseTargetToBomb(targets) {\n  // assert targets is a nonempty array of nonempty strings\n  T(ty.arr.ne.of(ty.str.ne))(targets);\n\n  ...\n\n  return T(ty.str.ne)(result); // assert we're returning a nonempty string\n}\n\nfunction getTRexFenceVoltage(fence) {\n  // assert that fence is an object with exactly two keys: sector, a nonempty\n  // string, and subsector, a non-negative integer.\n  T(ty.obj.of({sector: ty.str.ne, subsector: ty.int.nonneg}))(fence);\n\n  ...\n\n  return T(ty.num.finite)(voltage); // assert we're returning a finite number\n}\n\n// Declare a function that takes a finite number and a boolean as arguments,\n// and returns a finite number (finite*bool -\u003e finite). Runtime assertions\n// will fail if any of those types do not match, or if the wrong number of\n// arguments is passed.\nvar F = ty.WrapFun;\nvar moveNuclearControlRods = F([ty.num.finite, ty.bool], ty.num.finite,\n  function(position, scram) {\n    ...\n\n    return coreTemperature;\n  });\n```\n\n# Manual\n\nThe examples all assume the preamble\n\n```\nvar ty = require(\"assert-type\");\n```\n\n## Simple type predicates\n\nAt the foundation, the library provides simple functions that take a value and\nreturn a boolean indicating whether the value satisfies a specific type,\nessentially similar to those found in [many](http://underscorejs.org/)\n[other](https://github.com/visionmedia/should.js/)\n[libraries](https://github.com/mcavage/node-assert-plus). Don't worry, things\nget a bit more interesting down below.\n\n- `bool` boolean\n- `num` number (includes `NaN`)\n- `num.not.nan` any number but `NaN`\n- `num.pos` positive real number (excludes `NaN`)\n- `num.neg`\n- `num.nonneg`\n- `num.finite` real number `x` and `Number.NEGATIVE_INFINITY \u003c x \u003c Number.POSITIVE_INFINITY`\n- `num.finite.pos`\n- `num.finite.neg`\n- `num.finite.nonneg`\n- `int` integer (excludes `NaN` and infinite)\n- `int.pos`\n- `int.neg`\n- `int.nonneg`\n- `str` string\n- `str.ne` nonempty string\n- `arr` array\n- `arr.ne` nonempty array\n- `obj` object (includes null and arrays)\n- `obj.not.null` non-null object (includes arrays)\n- `inst.of(Cons)` test `instanceof Cons` (e.g. `Array`, `Date`, or your class)\n- `fun` function\n- `funN(n)` function of `n` arguments\n- `null` exactly `null` (mainly for use with `or`)\n- `undefined` exactly `undefined` (ditto)\n- `any` always true\n\nClearly, the types are not mutually exclusive.\n\n## Assert\n\nThe `Assert` function takes a type predicate and returns a function that takes\na value and asserts the value satisfies the predicate. If the assertion\nsucceeds, the value is also returned. This is easier to show by example:\n\n```\nvar T = ty.Assert;           // since we use it often\n\nT(ty.bool)(true);            // OK\nT(ty.bool)(0);               // throws ty.TypeAssertionError\n\nvar x = T(ty.num.finite)(0); // now x === 0\nT(ty.num.finite)(NaN);       // throws ty.TypeAssertionError\n\n// OK:\nT(ty.funN(1))(function (x) { return x; });\n// throws ty.TypeAssertionError:\nT(ty.funN(1))(function () { return 0; });\n```\n\n`Assert` also understands multiple types followed by matching values:\n\n```\nT(ty.bool, ty.int)(true, 1);   // OK\nT(ty.bool, ty.int)(true, 1.1); // throws ty.TypeAssertionError\n```\n\n## Composite types\n\nThe libary provides powerful operators for composing simple types into more\ncomplex ones.\n\n### or\n\n`or(ty1, ty2, ...)` returns a type predicate satisfied if any of the provided\npredicates are satisfied:\n\n```\nT(ty.or(ty.int, ty.bool))(3);    // OK\nT(ty.or(ty.int, ty.bool))(true); // OK\nT(ty.or(ty.int, ty.bool))(\"\");   // throws ty.TypeAssertionError\n```\n\n### arr.of and arr.ne.of\n\n`arr.of(somety)` returns a type predicate satisfied for arrays of the given\ntype.\n\n```\nT(ty.arr.of(ty.int))([1, 2, 3]); // OK\nT(ty.arr.of(ty.int))([]);        // vacuously OK\nT(ty.arr.of(ty.int))([true]);    // throws ty.TypeAssertionError\nT(ty.arr.of(ty.int))(null);      // throws ty.TypeAssertionError\n```\n\n`arr.ne.of(somety)` rejects the empty array.\n\nAn alternative usage of `arr.of` tests for an array with a specific number of\nelements of specific types.\n\n```\nT(ty.arr.of([ty.int, ty.bool]))([1, true]); // OK\nT(ty.arr.of([ty.int, ty.bool]))([1]);       // throws ty.TypeAssertionError\nT(ty.arr.of([ty.int, ty.bool]))([1, 2]);    // throws ty.TypeAssertionError\n```\n\n### obj.of and obj.with\n\n`obj.of(proto)`, where `proto` is an object with keys mapping to types,\nreturns a type predicate testing whether an object has exactly those keys\nand values satisfying the respective types.\n\n```\nT(ty.obj.of({x: ty.int, y: ty.int}))({x: 1, y: 2});       // OK\nT(ty.obj.of({x: ty.int, y: ty.int}))({x: 1, y: true});    // throws ty.TypeAssertionError\nT(ty.obj.of({x: ty.int, y: ty.int}))({x: 1});             // throws ty.TypeAssertionError\nT(ty.obj.of({x: ty.int, y: ty.int}))({x: 1, y: 2, z: 3}); // throws ty.TypeAssertionError\n```\n\n`obj.with(proto)` is similar, but permits and ignores keys in addition to\nthose specified in `proto`.\n\n### Sum types\n\nThe composite types formed by the above operators can themselves be composed.\nFor example, here's a simple sum type (tagged union) for 2D points in either\nCartesian or polar coordinates:\n\n```\nvar tCartesian = ty.obj.of({x: ty.num.finite, y: ty.num.finite});\nvar tPolar = ty.obj.of({r: ty.num.finite.nonneg, theta: ty.num.finite.nonneg});\nvar tPoint = ty.or(tCartesian, tPolar);\n\nfunction distanceToOrigin(pt) {\n  T(tPoint)(pt);\n  if (tCartesian(pt)) {\n    return Math.sqrt(pt.x*pt.x, pt.y*pt.y);\n  } else if (tPolar(pt)) {\n    return pt.r;\n  } else {\n    // should never happen\n    assert(false);\n  }\n}\n```\n\nAs this example hints, types are values that can be assigned and passed around\nat runtime. But it is not currently possible to declare recursive types,\nlimiting the scope of supported algebraic data types. I'm thinking about this.\n\n## Typed functions\n\n`fun.of([ty1, ty2, ...], tyRet)` is the type of a function whose arguments\nhave types `ty1, ty2, ...` and which returns a value of `tyRet`.\n\nFunctions with `fun.of(...)` types can only be generated by `WrapFun`, which\nwraps a given function so that type assertions about its arguments and return\nvalue are performed automatically before and after calling it.\n\n```\nvar F = ty.WrapFun;\n\nvar t = ty.fun.of([ty.int, ty.bool], ty.int);\nvar intFn = F(t, function(x, b) {\n                if (b) return 0-x; else return x;\n            });\nintFn(3, false); // returns 3\nintFn(3, true);  // returns -3\nintFn(3, \"\");    // throws ty.TypeAssertionError\nintFn(3);        // throws ty.TypeAssertionError\n\n// throws ty.TypeAssertionError due to wrong return value type:\nF(t, function(x, b) { return true; })(3, false);\n\n// OK:\nT(t)(intFn);\n// throws TypeAssertionError, since intFn has a different return type:\nT(ty.fun.of([ty.int, ty.bool], ty.bool))(intFn);\n```\n\n`intFn` could have been declared with the following shorter syntax, in which\nthe use of `ty.fun.of` is implicit:\n\n```\nvar intFn = F([ty.int, ty.bool], ty.int, function(x, b) {\n              if (b) return 0-x; else return x;\n            });\n```\n\nThere's also a simple predicate `fun.typed` to check whether a given function\nwas generated by `WrapFun`. Any JavaScript function will satisfy `fun`, any\nfunction generated by `WrapFun` will satisfy `fun.typed`, and only functions\ngenerated by `WrapFun` with the _exact_ same signature will satisfy\n`fun.of(...)`.\n\n## Typed functions with callbacks\n\nThere are a few ways to use `WrapFun` with functions that return values\nthrough callbacks (continuation passing style). First, if you're writing the\ncallback, you can guard the callback itself:\n\n```\nvar F = ty.WrapFun;\nvar fs = require(\"fs\");\n\nfs.readFile(\"file.txt\", \"utf-8\",\n  F([ty.any, ty.str], ty.any, function(err, txt) {\n    ...\n  }));\n```\n\nOne could further refine the signature of the callback to something like\n`ty.fun.of([ty.or(ty.undefined, ty.null, ty.inst.of(Error)), ty.str],\nty.undefined)`. In either case, a type mismatch of the return value would\nresult in a thrown `ty.TypeAssertionError`.\n\nSecond, for writing a CPS function, there's a `WrapFun_` variant for the\nnode.js asynchronous calling convention, where the callback is of the form\n`function (error, result) { ... }`.\n\n```\nvar F_ = ty.WrapFun_;\n\nvar intFn_ = F_([ty.int, ty.bool, ty.fun], ty.int, function (x, b, cb) {\n                if (b) cb(null, 0-x); else cb(null, x);\n              });\n\nintFn_(3, false, function(error, result) {\n  // result === 3\n});\nintFn_(3, true, function(error, result) {\n  // result === -3\n});\nintFn_(3, \"\", function(error, result) {}); // throws ty.TypeAssertionError\n\nF_([ty.fun], ty.int, function(cb) { return cb(null, true); })(function (error, result) {\n  // error is a ty.TypeAssertionError\n});\n```\n\n`WrapFun_` uses the return type to constrain the second argument to the\ncallback, and ignores the actual JavaScript return value of the function. Note\nthat the callback must still be represented explicitly as the last argument to\nthe function. As above, the type of the callback could be specified more\nprecisely, but this would require the callback to also be generated by\n`WrapFun`.\n\nIf a type assertion fails on the arguments, a regular JavaScript exception is\nthrown, since one can't be sure the callback is even present in this case. If\nthe type assertion fails on the return value, the resulting error is passed to\nthe callback.\n\nIn addition to `WrapFun_` there's also `_WrapFun` for functions that take the\ncallback as the first argument rather than the last (useful for\n[streamline.js](https://github.com/Sage/streamlinejs) code).\n\nThird and lastly, to write CPS functions not following the typical calling\nconvention, one can simply use the pass-through property of `Assert` to guard\nthe return value. For example, a function whose callback only accepts the\nreturn value:\n\n```\nvar d = F([ty.num.finite, ty.num.finite, ty.fun], ty.any, function(x, y, cb) {\n  return cb(T(ty.num.finite)(Math.sqrt(x*x + y*y)));\n});\n```\n\n## Type introspection\n\nThe TypeOf, Name, and Describe functions make it possible to identify types at\nruntime. (I'm still thinking through these features, so they may evolve\nsignificantly.)\n\n```\nty.Name(ty.TypeOf(0)));              // =\u003e 'num'\nty.Name(ty.TypeOf(ty.Name));         // =\u003e 'fun.of([type], str.ne)'\nty.Describe(ty.TypeOf(ty.Describe)); // =\u003e '(type) -\u003e nonempty string'\n\nvar myty = ty.fun.of([ty.arr.of(ty.int), ty.str.ne], ty.bool);\n\nty.Name(myty);                       // =\u003e 'fun.of([arr.of(int), str.ne], bool)'\nty.Describe(myty);                   // =\u003e '(integer array, nonempty string) -\u003e boolean'\n```\n\n# Wish list\n\n- Optional function arguments and object fields\n- Variadic functions and arrays\n- Recursive types --\u003e ADTs\n- Polymorphic functions and type variables\n- Flesh out obj.with as a module signature\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmlin%2Fnode-assert-type","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmlin%2Fnode-assert-type","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmlin%2Fnode-assert-type/lists"}