{"id":21747462,"url":"https://github.com/charlespascoe/typed-validation","last_synced_at":"2025-04-13T06:51:09.256Z","repository":{"id":57390230,"uuid":"104388185","full_name":"charlespascoe/typed-validation","owner":"charlespascoe","description":"Strongly-Typed Validators for TypeScript","archived":false,"fork":false,"pushed_at":"2023-05-21T16:48:04.000Z","size":123,"stargazers_count":4,"open_issues_count":1,"forks_count":1,"subscribers_count":1,"default_branch":"develop","last_synced_at":"2025-04-12T22:45:57.296Z","etag":null,"topics":["static-typing","typescript","validation","validation-library"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"lgpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/charlespascoe.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":"2017-09-21T19:10:04.000Z","updated_at":"2024-08-29T14:50:32.000Z","dependencies_parsed_at":"2022-09-15T05:11:27.062Z","dependency_job_id":null,"html_url":"https://github.com/charlespascoe/typed-validation","commit_stats":null,"previous_names":["cpascoe95/typed-validation","cpascoe95/validate-interface"],"tags_count":25,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/charlespascoe%2Ftyped-validation","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/charlespascoe%2Ftyped-validation/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/charlespascoe%2Ftyped-validation/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/charlespascoe%2Ftyped-validation/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/charlespascoe","download_url":"https://codeload.github.com/charlespascoe/typed-validation/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248675458,"owners_count":21143766,"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":["static-typing","typescript","validation","validation-library"],"created_at":"2024-11-26T08:09:12.845Z","updated_at":"2025-04-13T06:51:09.236Z","avatar_url":"https://github.com/charlespascoe.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![npm](https://img.shields.io/npm/v/typed-validation.svg)](https://www.npmjs.com/package/typed-validation)\n[![npm](https://img.shields.io/npm/dt/typed-validation.svg)](https://www.npmjs.com/package/typed-validation)\n[![npm](https://img.shields.io/npm/l/typed-validation.svg)](https://www.npmjs.com/package/typed-validation)\n\n# Strongly-Typed Validators for TypeScript\n\nIn TypeScript, `JSON.parse` returns type `any`, which isn't useful if you want type safety - if you're using TypeScript, you probably do.\n\n`typed-validation` lets you build build validators that TypeScript can understand, meaning that TypeScript can check that your validator aligns with the type it's supposed to be validating - no need to force types using [type assertion](https://basarat.gitbooks.io/typescript/docs/types/type-assertion.html)!\n\n## Installation ##\n\n`$ npm install --save typed-validation`\n\n*Note:* When using this module in a TypeScript project, 0.8.1 and later versions of this module require TypeScript 2.8 or above.\n\n## Basic Usage ##\n\n**Example:** check that a value of type `any` (perhaps from an untrusted source, such as a file) is an object that conforms to an interface called `Employee`:\n\n```ts\n// 1) Define the interface\ninterface Employee {\n  name: string;\n  roleCode: number;\n  completedTraining?: boolean;\n  addressPostcode: string;\n}\n\n// 2) Define the validator\nconst employeeValidator: Validator\u003cEmployee\u003e = {\n  name: isString(minLength(1)),\n  roleCode: isNumber(min(1, max(10))),\n  completedTraining: optional(isBoolean()),\n  addressPostcode: isString(matches(/^[a-z]{2}\\d{1,2}\\s+\\d{1,2}[a-z]{2}$/i))\n};\n\n// 3) Validate\n\nconst unsafeObject: any = {\n  name: 'Bob Smith',\n  roleCode: 7,\n  completedTraining: true,\n  addressPostcode: 'AB1 2CD'\n};\n\nconst result = validate(unsafeObject, conformsTo(employeeValidator));\n\nif (result.success) {\n  const bob = result.value;\n  const name = bob.name;\n}\n\n// Handle errors\n\nconst unsafeObject2: any = {\n  name: 'Name',\n  roleCode: 4,\n  completedTraining: 'false',\n  addressPostcode: 'WRONG'\n};\n\nconst result2 = validate(unsafeObject2, conformsTo(employeeValidator));\n\nif (!result2.success) {\n  console.log(result2.toString());\n}\n// Outputs:\n// 2 validation errors:\n//   $.completedTraining: Expected boolean, got string\n//   $.addressPostcode: Failed regular expression /^[a-z]{2}\\d{1,2}\\s+\\d{1,2}[a-z]{2}$/i\n\n```\n\n## Overview ##\nValidators are built by combining simple assertions using function composition and higher-order functions. For example, the `isString()` assertion returns a function which accepts a single argument of type `any` and returns either a `SuccessResult\u003cstring\u003e` or an `ErrorResult`. It will return `SuccessResult\u003cstring\u003e` if and only if the argument is a string, or an `ErrorResult` otherwise. This module provides a number of assertions, described below.\n\nAn assertion may take another assertion as its last argument; if assertion check passes, it calls the next assertion. For example, `isString(minLength(1, maxLength(10)))` first checks if the value is a string, then checks if its length is at least 1, and then checks that its length is no more than 10. If `isString` fails, `minLength` isn't run. Chaining assertions in this way allows for complex validation of types and values.\n\nSome assertions require other assertions to come before it. For example, `minLength` can't be used by itself because it needs another assertion to check that the value has the `length` property - so something like `isString(minLength(1))` or `isArray(minLength(1))`.\n\nJump to section:\n- [validate](#validate)\n- [Handling Validation Errors](#handling-validation-errors)\n- [Validator](#validator)\n- [extendValidator](#extendvalidator)\n\nAssertions:\n- [conformsTo](#conformsto)\n- [optional](#optional)\n- [nullable](#nullable)\n- [defaultsTo](#defaultsto)\n- [onErrorDefaultsTo](#onerrordefaultsto)\n- [isBoolean](#isboolean)\n- [isNumber](#isnumber)\n- [min](#min)\n- [max](#max)\n- [isString](#isstring)\n- [matches](#matches)\n- [minLength](#minlength)\n- [maxLength](#maxlength)\n- [lengthIs](#lengthis)\n- [isArray](#isarray)\n- [eachItem](#eachitem)\n- [isObject](#isobject)\n- [equals](#equals)\n- [isMap](#ismap)\n- [eachValue](#eachvalue)\n- [either](#either)\n\n### validate ###\n\nThe `validate` function takes two arguments; the first is the argument to validate, the second is an assertion. It returns a result object; if `result.success` is `true`, then `result.value` contains the validated value. If `result.success` is false, then `result.errors` contains the list of errors, which can be formatted by calling `result.toString()`.\n\n```ts\nconst result = vaildate(argumentToValidate, isString(minLength(1)));\n\nif (result.success) {\n  const validated: string = result.value;\n  console.log(`The validated result is: ${validated}`);\n} else {\n  console.log(`Validation failed: ${result.toString()}`);\n}\n```\n\n### Handling Validation Errors ###\n\nWhen validatin fails, `validate` will always return an `ErrorResult` object, which has a property `errors: ValidationError[]`.\n\nThe `ValidationError` type has a number of useful properties:\n\n- `errorCode`: A string which is one of a set of error codes, e.g. `NOT_STRING`. Useful for producing custom error messages or triggering certain error logic.\n- `message`: A human-readable error message, with more information as to why the validation failed.\n- `path`: An array of objects that describe the path to the value that caused the validation to fail. Each object is either an `ArrayIndexPathNode` (which has an `index` property) or `KeyPathNode` (which has a `key` property).\n\nThe `ErrorResult.toString()` method prints this information in a human-readable format. The name of the root object defaults to `$`, but this can be changed by passing a string, e.g. `err.toString('this')`.\n\n### Validator ###\n\n`Validator` is a type that enables TypeScript to validate that the validator correctly aligns to the interface it is supposed to validate.\n\nThe keys of the validator align with the keys of the interface. The values of the validator are a chain of assertions.\n\n```ts\ninterface IFoo {\n  bar: string;\n  baz: number;\n}\n\n// A valid validator\nconst fooValidator: Validator\u003cIFoo\u003e = {\n  bar: isString(),\n  baz: isNumber()\n};\n\n// All of these are invalid, and will result in an error from the TypeScript compiler\n\nconst fooValidator: Validator\u003cIFoo\u003e = {\n  bar: isString()\n}; // Missing 'baz'\n\nconst fooValidator: Validator\u003cIFoo\u003e = {\n  bar: isNumber(), // Wrong type\n  baz: isNumber()\n};\n\nconst fooValidator: Validator\u003cIFoo\u003e = {\n  bar: isString(),\n  baz: isNumber(),\n  blah: isBoolean() // Unexpected property\n};\n\n```\n\n### extendValidator ###\nTakes two validators and returns a new validator that validates the intersection type of `T` and `U` - useful for extending existing validators to prevent repetition.\n\nExample:\n\n```ts\ninterface IFoo {\n  abc: number;\n}\n\nconst fooValidator: Validator\u003cIFoo\u003e = {\n  abc: isNumber()\n};\n\ninterface IBar extends IFoo {\n  xyz: string;\n}\n\nconst barValidator: Validator\u003cIBar\u003e = extendValidator(fooValidator, {\n  xyz: isString()\n});\n```\n\n\n### conformsTo ###\nReturns an error if the value does not conform to the given validator.\n\n```ts\ninterface IFoo {\n  bar: number;\n}\n\nconst fooValidator: Validator\u003cIFoo\u003e = {\n  bar: isNumber()\n};\n\n// Returns a success result\nvalidate({bar: 123}, conformsTo(fooValidator));\n\n// Returns an error result\nvalidate({bar: 'example'}, conformsTo(fooValidator));\n```\n\nThe third argument is an optional object of options:\n\n- `allowAdditionalProperties: boolean` - If false, returns an error if there are any properties in addition to the ones defined in the validator. Defaults to `true`, which removes additional properties from the result.\n\n```ts\nconst result1 = validate({foo: 'abc', bar: 123}, conformsTo(fooValidator));\n\nif (result1.success) {\n  console.log(result1.value); // {bar: 123}\n}\n\nconst result2 = validate({foo: 'abc', bar: 123}, conformsTo(fooValidator, {allowAdditionalProperties: false}));\n\nif (!result2.success) {\n  console.log(result2.toString())\n  // 1 validation error:\n  //   $: Unexpected additional properties: foo\n}\n```\n\n\n### optional ###\nUsed when the properties may not present on the object, or its value is undefined. Example:\n\n```ts\ninterface IFoo {\n  bar?: string;\n  // You can also use 'undefined' in a union type\n  baz: number | undefined;\n}\n\nconst fooValidator: Validator\u003cIFoo\u003e = {\n  bar: optional(isString()),\n  baz: optional(isNumber())\n};\n\n// Both of these are acceptable\nvalidate({}, conformsTo(fooValidator));\nvalidate({bar: undefined}, conformsTo(fooValidator));\n```\n\n### nullable ###\nUsed when the value could be null (e.g. `prop: T | null`).\n\n```ts\ninterface IFoo {\n  bar: string | null;\n}\n\nconst fooValidator: Validator\u003cIFoo\u003e = {\n  bar: nullable(isString()),\n};\n```\n\n\n### defaultsTo ###\nIf the property on the object being validated is undefined, then return the given default value instead.\n\n```ts\ninterface IFoo {\n  bar: string;\n}\n\nconst fooValidator: Validator\u003cIFoo\u003e = {\n  bar: defaultsTo('baz', isString()),\n};\n\nconst result = validate({}, conformsTo(fooValidator));\n\nif (result.success) {\n  console.log(result.value);\n}\n\n// Output:\n// {bar: 'baz'}\n```\n\n**Note:** the default value will get passed through the assertion chain.\n\n### onErrorDefaultsTo ###\nIf the following assertion chain fails, then return the given value instead.\n\n```ts\ninterface IFoo {\n  bar: string;\n}\n\nconst fooValidator: Validator\u003cIFoo\u003e = {\n  bar: onErrorDefaultsTo('baz', isString()),\n};\n\nconst result = validate({bar: 123}, conformsTo(fooValidator));\n\nif (result.success) {\n  console.log(result.value);\n}\n\n// Output:\n// {bar: 'baz'}\n```\n\n### isBoolean ###\nReturns an error if the value is not a boolean.\n\n### isNumber ###\nReturns an error if the value is not a number.\n\n### min ###\nReturns an error if the value is less than the given minimum.\n\n```ts\ninterface IFoo {\n  bar: number;\n}\n\nconst fooValidator: Validator\u003cIFoo\u003e = {\n  bar: isNuber(min(0))\n};\n\n// Returns an error result\nconst result = validate({bar: -1}, conformsTo(fooValidator));\n```\n\n### max ###\nReturns an error if the value is greater than the given maximum - see [min](#min).\n\n### isString ###\nReturns an error if the value is not a string.\n\n### matches ###\nReturns an error if the string value does not match the given regex.\n\n```ts\ninterface IFoo {\n  bar: string;\n}\n\nconst fooValidator: Validator\u003cIFoo\u003e = {\n  bar: isStirng(matches(/^[a-z]+$/))\n};\n\n// Returns an error result\nconst result = validate({bar: '123abc'}, conformsTo(fooValidator));\n```\n\n### minLength ###\nReturns an error if length of the value (e.g. a string or an array) is less than the given minimum.\n\n```ts\ninterface IFoo {\n  bar: string;\n}\n\nconst fooValidator: Validator\u003cIFoo\u003e = {\n  bar: isStirng(minLength(1))\n};\n\n// Returns an error result\nconst result = validate({bar: ''}, conformsTo(fooValidator));\n```\n\n### maxLength ###\nReturns an error if length of the value (e.g. a string or an array) is less than the given maximum - see [minLength](#minlength).\n\n### lengthIs ###\nReturns an error if length of the value (e.g. a string or an array) is not equal to the given length - see [minLength](#minlength).\n\n### isArray ###\nReturns an error if the value is not an array. If no other assertions are given, then the type defaults to `any[]`.\n\n```ts\ninterface IFoo {\n  bar: any[];\n}\n\nconst fooValidator: Validator\u003cIFoo\u003e = {\n  bar: isArray()\n};\n\n// This is valid\nvalidate({\n  bar: ['abc', 123, true, null]\n}, conformsTo(fooValidator));\n\n// Returns an error\nvalidate({\n  bar: 'baz'\n}, conformsTo(fooValidator));\n```\n\n### eachItem ###\nReturns an error if any value of an array does not match the following assertion chain.\n\n```ts\ninterface IFoo {\n  bar: number[];\n}\n\nconst fooValidator: Validator\u003cIFoo\u003e = {\n  bar: isArray(eachItem(isNumber()))\n};\n\n// This is valid\nvalidate({\n  bar: [1, 2, 3]\n}, conformsTo(fooValidator));\n\n// Returns an error\nvalidate({\n  bar: ['abc', 123, true, null]\n}, conformsTo(fooValidator));\n```\n\n### isObject ###\nReturns an error if the value is not an object.\n\n```ts\ninterface IFoo {\n  bar: any;\n}\n\nconst fooValidator: Validator\u003cIFoo\u003e = {\n  bar: isObject()\n};\n\n// This is valid, but it wouldn't be safe to access properties on foo.bar\nconst foo = validate({\n  bar: {baz: 123}\n}, conformsTo(fooValidator));\n\n// Returns an error\nvalidate({\n  bar: 'object'\n}, conformsTo(fooValidator));\n```\n\n### equals ###\nReturns an error if the value does not equal one of the given values.\n\n```ts\ntype Bar = 'A' | 'B' | 'C';\n\ninterface IFoo {\n  bar: Bar;\n}\n\nconst fooValidator: Validator\u003cIFoo\u003e = {\n  bar: equals\u003cBar\u003e('A', 'B', 'C')\n};\n\n// Returns an error\nvalidate({\n  bar: 'D'\n}, conformsTo(fooValidator));\n```\n\n### isMap ###\nValidates that the result is a map of `string` onto `any`.\n\n```ts\ninterface IFoo {\n  map: {[key: string]: any};\n}\n\nconst fooValidator: Validator\u003cIFoo\u003e = {\n  map: isMap()\n};\n\n// This is valid\nvalidate({\n  map: {\n    bar: 'ABC',\n    baz: {x: 123, y: 456},\n    blah: null\n  }\n}, conformsTo(fooValidator));\n\n// This is also valid\nvalidate({\n  map: { }\n}, conformsTo(fooValidator));\n\n// Returns an error - not an object\nvalidate({\n  map: 'abc'\n}, conformsTo(fooValidator));\n\n// Returns an error - one of the keys is not a string\nvalidate({\n  map: {\n    bar: 'ABC',\n    baz: {x: 123, y: 456},\n    0: true\n  }\n}, conformsTo(fooValidator));\n```\n\n### eachValue ###\nReturns an error if any value of a map does not match the following assertion chain.\n\n```ts\ninterface IFoo {\n  map: {[key: string]: string};\n}\n\nconst fooValidator: Validator\u003cIFoo\u003e = {\n  map: isMap(eachValue(isString(minLength(1))))\n};\n\n// This is valid\nvalidate({\n  map: {\n    bar: 'ABC',\n    'a very long key with spaces': 'DEF'\n  }\n}, conformsTo(fooValidator));\n\n// Returns an error result\nvalidate({\n  map: {\n    bar: true, // Not a string\n    baz: ''    // Too short\n  }\n}, conformsTo(fooValidator));\n```\n\n### either ###\nChecks against multiple assertions until either one is valid, or they all fail. Useful for complex union types. Assertions are checked in the order given.\n\nWhen no match is found, all the validation errors for each type are printed.\n\n```ts\ninterface IFoo {\n  bar: string | string[];\n}\n\nconst fooValidator: Validator\u003cIFoo\u003e = {\n  bar: either(\n    is('a letter', isString(lengthIs(1))),\n    is('an array of letters', isArray(eachItem(isString(lengthIs(1)))))\n  )\n};\n\n// These are valid\nvalidate({bar: 'A'}, conformsTo(fooValidator));\nvalidate({bar: ['A', 'B', 'C']}, conformsTo(fooValidator));\n\n// An invalid example\n\nconst result = validate({bar: ['A', 'BC', 'D']}, conformsTo(fooValidator));\n\nif (!result.success) {\n    console.log(result.toString());\n    // 1 validation error:\n    //     $.bar: No match found - the following assertions failed:\n    //         Not a letter, due to 1 validation error:\n    //             $: Expected string, got array\n    //         Not an array of letters, due to 1 validation error:\n    //             $[1]: Length 2 is not equal to 1\n}\n```\n\n**Note:** Due to limitations with generics, currently up to 20 assertions are supported by TypeScript.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcharlespascoe%2Ftyped-validation","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcharlespascoe%2Ftyped-validation","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcharlespascoe%2Ftyped-validation/lists"}