{"id":13847215,"url":"https://github.com/GoogleFeud/ts-runtime-checks","last_synced_at":"2025-07-12T08:31:27.950Z","repository":{"id":42570680,"uuid":"472468962","full_name":"GoogleFeud/ts-runtime-checks","owner":"GoogleFeud","description":"A typescript transformer that automatically generates validation code from your types.","archived":false,"fork":false,"pushed_at":"2025-01-15T18:53:42.000Z","size":17428,"stargazers_count":384,"open_issues_count":10,"forks_count":9,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-07-08T20:47:13.919Z","etag":null,"topics":["runtime","transformer","typescript","validation"],"latest_commit_sha":null,"homepage":"https://googlefeud.github.io/ts-runtime-checks/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/GoogleFeud.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-03-21T18:45:36.000Z","updated_at":"2025-06-13T07:42:05.000Z","dependencies_parsed_at":"2023-10-15T07:52:22.544Z","dependency_job_id":"d750d62a-b54c-47fe-b3c1-8e636208985d","html_url":"https://github.com/GoogleFeud/ts-runtime-checks","commit_stats":{"total_commits":289,"total_committers":3,"mean_commits":96.33333333333333,"dds":0.00692041522491349,"last_synced_commit":"8e76875200490609ef0d887fd025b7ec51722efb"},"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"purl":"pkg:github/GoogleFeud/ts-runtime-checks","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GoogleFeud%2Fts-runtime-checks","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GoogleFeud%2Fts-runtime-checks/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GoogleFeud%2Fts-runtime-checks/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GoogleFeud%2Fts-runtime-checks/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/GoogleFeud","download_url":"https://codeload.github.com/GoogleFeud/ts-runtime-checks/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GoogleFeud%2Fts-runtime-checks/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264962216,"owners_count":23689763,"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":["runtime","transformer","typescript","validation"],"created_at":"2024-08-04T18:01:13.500Z","updated_at":"2025-07-12T08:31:26.735Z","avatar_url":"https://github.com/GoogleFeud.png","language":"TypeScript","readme":"# ts-runtime-checks\n\nA typescript transformer which automatically generates validation code from your types. Think of it as a validation library like [ajv](https://ajv.js.org/guide/typescript.html) and [zod](https://zod.dev/), except it completely relies on the typescript compiler, and generates vanilla javascript code on demand. This comes with a lot of advantages:\n\n-   It's just types - no boilerplate or schemas needed.\n-   Only validate where you see fit.\n-   Code is generated during the transpilation phase, and can be easily optimized by V8.\n-   Powerful - built on top of typescript's type system, which is turing-complete.\n\nHere are some examples you can try out in the [playground](https://googlefeud.github.io/ts-runtime-checks/):\n\n**Asserting function parameters:**\n\n```ts\n// Special `Assert` type get detected and generates validation code\nfunction greet(name: Assert\u003cstring\u003e, age: Assert\u003cnumber\u003e): string {\n    return `Hello ${name}, you are ${age} years old!`;\n}\n\n// Transpiles to:\nfunction greet(name, age) {\n    if (typeof name !== \"string\") throw new Error(\"Expected name to be a string\");\n    if (typeof age !== \"number\") throw new Error(\"Expected age to be a number\");\n    return `Hello ${name}, you are ${age} years old!`;\n}\n```\n\n**Checking whether a value is of a certain type:**\n\n```ts\ninterface User {\n    name: string;\n    age: Min\u003c13\u003e;\n}\n\nconst maybeUser = {name: \"GoogleFeud\", age: \"123\"};\n// `is` function transpiles to the validation code\nconst isUser = is\u003cUser\u003e(maybeUser);\n\n// Transpiles to:\nconst isUser = typeof maybeUser === \"object\" \u0026\u0026 maybeUser !== null \u0026\u0026 typeof maybeUser.name === \"string\" \u0026\u0026 typeof maybeUser.age === \"number\" \u0026\u0026 maybeUser.age \u003e 13;\n```\n\n**Pattern Matching:**\n\n```ts\ntype WithValue = {value: string};\n// `createMatch` function creates a pattern-matching function\nconst extractString = createMatch\u003cstring\u003e([\n    (value: string | number) =\u003e value.toString(),\n    ({value}: WithValue) =\u003e value,\n    () =\u003e {\n        throw new Error(\"Could not extract string.\");\n    }\n]);\n\n//Transpiles to:\nconst extractString = value_1 =\u003e {\n    if (typeof value_1 === \"string\") return value_1.toString();\n    else if (typeof value_1 === \"number\") return value_1.toString();\n    else if (typeof value_1 === \"object\" \u0026\u0026 value_1 !== null) {\n        if (typeof value_1.value === \"string\") {\n            let {value} = value_1;\n            return value;\n        }\n    }\n    throw new Error(\"Could not extract string.\");\n};\n```\n\n## Usage\n\n```\nnpm i --save-dev ts-runtime-checks\n```\n\n\u003cdetails\u003e\n    \u003csummary\u003eUsage with ts-patch\u003c/summary\u003e\n\n```\nnpm i --save-dev ts-patch\n```\n\nand add the ts-runtime-checks transformer to your tsconfig.json:\n\n```json\n\"compilerOptions\": {\n//... other options\n\"plugins\": [\n        { \"transform\": \"ts-runtime-checks\" }\n    ]\n}\n```\n\nAfterwards you can either use the `tspc` CLI command to transpile your typescript code.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n    \u003csummary\u003eUsage with ts-loader\u003c/summary\u003e\n\n```js\nconst TsRuntimeChecks = require(\"ts-runtime-checks\").default;\n\noptions: {\n    getCustomTransformers: program =\u003e {\n        before: [TsRuntimeChecks(program)];\n    };\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n    \u003csummary\u003eUsage with ts-node\u003c/summary\u003e\n\nTo use transformers with ts-node, you'll have to change the compiler in the `tsconfig.json`:\n\n```\nnpm i --save-dev ts-patch\n```\n\n```json\n\"ts-node\": {\n    \"compiler\": \"ts-patch\"\n  },\n  \"compilerOptions\": {\n    \"plugins\": [\n        { \"transform\": \"ts-runtime-checks\" }\n    ]\n  }\n```\n\n\u003c/details\u003e\n\n## `ts-runtime-checks` in depth\n\n### Markers\n\nMarkers are typescript type aliases which are detected by the transformer. These types don't represent actual values, but they tell the transformer what code to generate. Think of them as functions!\n\nBy far the most important marker is `Assert\u003cT\u003e`, which tells the transpiler to validate the type `T`. There are also `utility` markers which can be used inside an `Assert` marker to customize the validation in some way or to add extra checks. Here's the list of all utility markers:\n\n-   `Check\u003cCondition, Error, Id, Value\u003e` - Checks if `Condition` is true for the value.\n-   `NoCheck\u003cType\u003e`- Doesn't generate checks for the provided type.\n-   `ExactProps\u003cObj, removeExtra, useDeleteOperator\u003e` - Makes sure the value doesn't have any excessive properties.\n-   `Expr\u003cstring\u003e` - Turns the string into an expression. Can be used in markers which require a javascript value.\n-   `Infer\u003cType\u003e` / `Resolve\u003cType\u003e` - Creating validation for type parameters.\n\nThe library also exports a set of built-in `Check` type aliases, which can be used on existing types to add extra checks:\n\n-   `Min\u003cSize\u003e` / `Max\u003cSize\u003e` - Check if a number is within bounds.\n-   `Int` / `Float` - Limit a number to integer / floating point.\n-   `Matches\u003cRegex\u003e` - Check if the value matches a pattern.\n-   `MaxLen\u003cSize\u003e` / `MinLen\u003cSize\u003e` / `Length\u003cSize\u003e` - Used with anything that has a `length` property to check if it's within bounds.\n-   `Eq` - Compares the value with the provided expression.\n-   `Not` - Negates a `Check`.\n\n#### `Assert\u003cType, Action\u003e`\n\nThe `Assert` marker asserts that a value is of the provided type by adding **validation code** that gets executed during runtime. If the value doesn't match the type, the code will either return a value or throw an error, depending on what `Action` is:\n\n-   Type literals (`123`, `\"hello\"`, `undefined`, `true`, `false`) - The literal will be returned.\n-   `Expr\u003cType\u003e` - The expression will be returned.\n-   `ErrorMsg\u003crawErrors\u003e` - The error message will be returned.\n-   `ThrowError\u003cErrorType, rawErrors\u003e` - An error of type `ErrorType` will be thrown.\n\nIf `rawErrors` is true, instead of an error string, the transformer will pass / return an object like this:\n\n```js\n{\n    // The value of the item that caused it\n    value: any;\n    // The name of the value\n    valueName: string;\n    // Information about the expected type\n    expectedType: TypeData;\n}\n```\n\nBy default, `ThrowError\u003cError\u003e` is passed to `Assert`.\n\n```ts\nfunction onMessage(msg: Assert\u003cstring\u003e, content: Assert\u003cstring, false\u003e, timestamp: Assert\u003cnumber, ThrowError\u003cRangeError, true\u003e\u003e) {\n    // ...\n}\n\nfunction onMessage(msg, content, timestamp) {\n    if (typeof msg !== \"string\") throw new Error(\"Expected msg to be a string\");\n    if (typeof content !== \"string\") return false;\n    if (typeof timestamp !== \"number\") throw new RangeError({value: timestamp, valueName: \"timestamp\", expectedType: {kind: 0}});\n}\n```\n\n#### `Check\u003cCondition, Error, ID, Value\u003e`\n\nAllows you to create custom conditions by providing a string containing javascript code, or a reference to a function.\n\n-   You can use the `$self` variable to get the value that's currently being validated.\n-   You can use the `$parent` function to get the parent object of the value. You can pass a number to get nested parents.\n\n`Error` is a custom error string message that will get displayed if the check fails.\n\n```ts\ntype StartsWith\u003cT extends string\u003e = Check\u003c`$self.startsWith(\"${T}\")`, `to start with \"${T}\"`, \"startsWith\", T\u003e;\n\nfunction test(a: Assert\u003cstring \u0026 StartsWith\u003c\"a\"\u003e\u003e) {\n    return true;\n}\n\n// Transpiles to:\nfunction test(a) {\n    if (typeof a !== \"string\" || !a.startsWith(\"a\")) throw new Error('Expected a to be a string, to start with \"a\"');\n    return true;\n}\n```\n\nYou can combine checks using the `\u0026` (intersection) operator:\n\n```ts\n// MaxLen and MinLen are types included in the library\nfunction test(a: Assert\u003cstring \u0026 StartsWith\u003c\"a\"\u003e \u0026 MaxLen\u003c36\u003e \u0026 MinLen\u003c3\u003e\u003e) {\n    return true;\n}\n\n// Transpiles to:\nfunction test(a) {\n    if (typeof a !== \"string\" || !a.startsWith(\"a\") || a.length \u003e 36 || a.length \u003c 3)\n        throw new Error('Expected a to be a string, to start with \"a\", to have a length less than 36, to have a length greater than 3');\n    return true;\n}\n```\n\nThe `ID` and `Value` type parameters get used when you want to receive a raw error. You don't need to use them if you don't make use of raw errors. They get passed to the `expectedType` object, where `ID` is the key and `Value` is the value:\n\n```ts\nfunction test(a: Assert\u003cstring \u0026 StartsWith\u003c\"a\"\u003e, ThrowError\u003cError, true\u003e\u003e) {\n    return 1;\n}\n\n// Transpiles to:\nfunction test(a) {\n    if (typeof a !== \"string\" || !a.startsWith(a)) throw new Error({value: a, valueName: \"a\", expectedType: {kind: 1, startsWith: \"a\"}});\n    return 1;\n}\n```\n\n#### `NoCheck\u003cType\u003e`\n\nSkips validating the value.\n\n```ts\ninterface UserRequest {\n    name: string;\n    id: string;\n    child: NoCheck\u003cUserRequest\u003e;\n}\n\nfunction test(req: Assert\u003cUserRequest\u003e) {\n    // Your code...\n}\n\n// Transpiles to:\nfunction test(req) {\n    if (typeof req !== \"object\" || req === null) throw new Error(\"Expected req to be an object\");\n    if (typeof req.name !== \"string\") throw new Error(\"Expected req.name to be a string\");\n    if (typeof req.id !== \"string\") throw new Error(\"Expected req.id to be a string\");\n}\n```\n\n#### `ExactProps\u003cType, removeExtra, useDeleteOperator\u003e`\n\nChecks if an object has any \"excessive\" properties (properties which are not on the type but they are on the object).\n\nIf `removeExtra` is true, then instead of an error getting thrown, any excessive properties will be deleted **in place** from the object.\n\nIf `useDeleteOperator` is true, then the `delete` operator will be used to delete the property, otherwise the property will get set to undefined.\n\n```ts\nfunction test(req: unknown) {\n    return req as Assert\u003cExactProps\u003c{a: string; b: number; c: [string, number]}\u003e\u003e;\n}\n\n// Transpiles to:\n\nfunction test(req) {\n    if (typeof req !== \"object\" || req === null) throw new Error(\"Expected req to be an object\");\n    if (typeof req.a !== \"string\") throw new Error(\"Expected req.a to be a string\");\n    if (typeof req.b !== \"number\") throw new Error(\"Expected req.b to be a number\");\n    if (!Array.isArray(req.c)) throw new Error(\"Expected req.c to be an array\");\n    if (typeof req.c[0] !== \"string\") throw new Error(\"Expected req.c[0] to be a string\");\n    if (typeof req.c[1] !== \"number\") throw new Error(\"Expected req.c[1] to be a number\");\n    for (let p_1 in req) {\n        if (p_1 !== \"a\" \u0026\u0026 p_1 !== \"b\" \u0026\u0026 p_1 !== \"c\") throw new Error(\"Property req.\" + p_1 + \" is excessive\");\n    }\n    return req;\n}\n```\n\n#### `Infer\u003cType\u003e`\n\nYou can use this utility type on type parameters - the transformer is going to go through all call locations of the function the type parameter belongs to, figure out the actual type used, create a union of all the possible types and validate it inside the function body.\n\n```ts\nexport function test\u003cT\u003e(body: Assert\u003cInfer\u003cT\u003e\u003e) {\n    return true;\n}\n\n// in fileA.ts\ntest(123);\n\n// in FileB.ts\ntest([1, 2, 3]);\n\n// Transpiles to:\nfunction test(body) {\n    if (typeof body !== \"number\")\n        if (!Array.isArray(body)) throw new Error(\"Expected body to be one of number, number[]\");\n        else {\n            for (let i_1 = 0; i_1 \u003c len_1; i_1++) {\n                if (typeof body[i_1] !== \"number\") throw new Error(\"Expected body[\" + i_1 + \"] to be a number\");\n            }\n        }\n    return true;\n}\n```\n\n#### `Resolve\u003cType\u003e`\n\nPass a type parameter to `Resolve\u003cType\u003e` to _move_ the validation logic to the call site, where the type parameter is resolved to an actual type.\n\nCurrently, this marker has some limitations:\n\n-   Can only be used in `Assert` markers (so you can't use it in `check` or `is`)\n-   Can only be used in parameter declarations (so no `as` assertions)\n-   The parameter name **has** to be an identifier (no deconstructions)\n-   Cannot be used on rest parameters\n\n```ts\nfunction validateBody\u003cT\u003e(data: Assert\u003c{body: Resolve\u003cT\u003e}\u003e) {\n    return data.body;\n}\n\nconst validatedBody = validateBody\u003c{\n    name: string;\n    other: boolean;\n}\u003e({body: JSON.parse(process.argv[2])});\n\n// Transpiles to:\nfunction validateBody(data) {\n    return data.body;\n}\nconst receivedBody = JSON.parse(process.argv[2]);\nconst validatedBody = (() =\u003e {\n    const data = {body: receivedBody};\n    if (typeof data.body !== \"object\" \u0026\u0026 data.body !== null) throw new Error(\"Expected data.body to be an object\");\n    if (typeof data.body.name !== \"string\") throw new Error(\"Expected data.body.name to be a string\");\n    if (typeof data.body.other !== \"boolean\") throw new Error(\"Expected data.body.other to be a boolean\");\n    return validateBody(data);\n})();\n```\n\n### Transformations\n\nYou can also describe **transformations** in your types using the `Transform` marker. It accepts a reference to a function, a string containing javascript code, or a combination of both:\n\n```ts\nconst timestampToDate = (ts: number) =\u003e new Date(ts);\nconst incrementAge = (age: number) =\u003e age + 1;\n\ntype User = {\n    username: string;\n    createdAt: Transform\u003ctypeof timestampToDate\u003e;\n    age: Transform\u003c[\"+$self\", typeof incrementAge], string\u003e;\n};\n```\n\nIt's recommended to use function references because all of the types will be inferred for you. In the example above, we're able to tell typescript that `createdAt` is of type `number` before it gets transformed to `Date`. However, in `age`, we have to specify the initial type (`string`) because the first transformation is a code string.\n\nOnce you have a type you can transform, you can use the `transform` utility function to actually perform the transformation:\n\n```ts\nconst myUser: User = {\n    username: \"GoogleFeud\",\n    createdAt: 1716657364400,\n    age: \"123\"\n}\n\nconsole.log(transform\u003cUser\u003e(myUser))\n\n// Transpiles to:\n\nlet result_1;\nresult_1 = {};\nresult_1.createdAt = timestampToDate(myUser.createdAt);\nresult_1.age = incrementAge(+myUser.age);\nresult_1.username = myUser.username;\nconsole.log(result_1);\n```\n\nThe second type parameter of the `transform` function is an `Action`, and if it's provided, the type will be validated before being transformed. Check out the `Assert` section for all possible actions.\n\nYou can also perform **conditional transformations** via unions:\n\n```ts\ninterface ConditionalTransform {\n    // \"age\" is either a number or a string\n    age: number | Transform\u003ctypeof stringToNum\u003e,\n    // \"id\" is either a string or a number that must be larger than 3.\n    id: Transform\u003ctypeof stringToNum\u003e | Min\u003c3\u003e \u0026 Transform\u003c\"$self + 1\"\u003e\n}\n\ntransform\u003cConditionalTransform, ThrowError\u003e({ age: \"3\", id: 12 })\n\n// Transpiles to:\nlet result_1;\nresult_1 = {};\nif (typeof value_1.id === \"string\") {\n    result_1.id = stringToNum(value_1.id);\n} else if (typeof value_1.id === \"number\" \u0026\u0026 value_1.id \u003e= 3) {\n    result_1.id = value_1.id + 1;\n} else\n    throw new Error(\"Expected value.id to be one of string | number, to be greater than 3\");\nif (typeof value_1.age === \"string\") {\n    result_1.age = stringToNum(value_1.age);\n} else if (typeof value_1.age === \"number\") {\n    result_1.age = value_1.age;\n} else\n    throw new Error(\"Expected value.age to be one of string | number\");\n```\n\nYou can also use the `PostCheck` type to perform checks after the value has been transformed! Check out the `PostCheck` examples and other pretty crazy conditional transformations [in this unit test](https://github.com/GoogleFeud/ts-runtime-checks/blob/main/tests/integrated/transforms.test.ts)\n\n### `as` assertions\n\nYou can use `as` type assertions to validate values in expressions. The transformer remembers what's safe to use, so you can't generate the same validation code twice.\n\n```ts\ninterface Args {\n    name: string;\n    path: string;\n    output: string;\n    clusters?: number;\n}\n\nconst args = JSON.parse(process.argv[2] as Assert\u003cstring\u003e) as Assert\u003cArgs\u003e;\n\n// Transpiles to:\nif (typeof process.argv[2] !== \"string\") throw new Error(\"Expected process.argv[2] to be a string\");\nconst value_1 = JSON.parse(process.argv[2]);\nif (typeof value_1 !== \"object\" || value_1 === null) throw new Error(\"Expected value to be an object\");\nif (typeof value_1.name !== \"string\") throw new Error(\"Expected value.name to be a string\");\nif (typeof value_1.path !== \"string\") throw new Error(\"Expected value.path to be a string\");\nif (typeof value_1.output !== \"string\") throw new Error(\"Expected value.output to be a string\");\nif (value_1.clusters !== undefined \u0026\u0026 typeof value_1.clusters !== \"number\") throw new Error(\"Expected value.clusters to be a number\");\nconst args = value_1;\n```\n\n### `is\u003cType\u003e(value)`\n\nEvery call to this function gets replaced with an immediately-invoked arrow function, which returns `true` if the value matches the type, `false` otherwise.\n\n```ts\nconst val = JSON.parse('[\"Hello\", \"World\"]');\nif (is\u003c[string, number]\u003e(val)) {\n    // val is guaranteed to be [string, number]\n}\n\n// Transpiles to:\n\nconst val = JSON.parse('[\"Hello\", \"World\"]');\nif (Array.isArray(val) \u0026\u0026 typeof val[0] === \"string\" \u0026\u0026 typeof val[1] === \"number\") {\n    // Your code\n}\n```\n\n### `check\u003cType, rawErrors\u003e(value)`\n\nEvery call to this function gets replaced with an immediately-invoked arrow function, which returns the provided value, along with an array of errors.\n\nIf `rawErrors` is true, the raw error data will be pushed to the array instead of error strings.\n\n```ts\nconst [value, errors] = check\u003c[string, number]\u003e(JSON.parse('[\"Hello\", \"World\"]'));\nif (errors.length) console.log(errors);\n\n// Transpiles to:\n\nconst value = JSON.parse('[\"Hello\", \"World\"]');\nconst errors = [];\nif (!Array.isArray(value)) errors.push(\"Expected value to be an array\");\nelse {\n    if (typeof value[0] !== \"string\") errors.push(\"Expected value[0] to be a string\");\n    if (typeof value[1] !== \"number\") errors.push(\"Expected value[1] to be a number\");\n}\nif (errors.length) console.log(errors);\n```\n\n### `createMatch\u003cReturnType, InputType\u003e(function[], noDiscriminatedObjAssert)`\n\nCreates a match function which performs pattern-matching on the input type, based on the provided functions. Each function in the array is a match arm, where the type of the first parameter is the type the arm is matching against:\n\n```ts\n// We want the match function to return a string and to accept a number\nconst resolver = createMatch\u003cstring, number\u003e([\n    // Match arm which catches the values 0 or 1\n    (_: 0 | 1) =\u003e \"not many\",\n    // Match arm which catches any number less than 9\n    (_: Max\u003c9\u003e) =\u003e \"a few\",\n    // Match arm which catches any number that hasn't already been caught\n    (_: number) =\u003e \"lots\"\n]);\n\n// Transpiles to:\nconst resolver = value_1 =\u003e {\n    if (typeof value_1 === \"number\") {\n        if (value_1 === 1 || value_1 === 0) return \"not many\";\n        else if (value_1 \u003c 9) return \"a few\";\n        else return \"lots\";\n    }\n};\n```\n\nYou could also have a default match arm by omitting the parameter, or giving it the `unknown` or `any` type:\n\n```ts\nconst toNumber: (value: unknown) =\u003e number = createMatch\u003cnumber\u003e([\n    (value: string | boolean) =\u003e +value,\n    (value: number) =\u003e value,\n    (value: Array\u003cstring\u003e | Array\u003cnumber\u003e | Array\u003cboolean\u003e) =\u003e value.map(v =\u003e toNumber(v)).reduce((val, acc) =\u003e val + acc, 0),\n    (value: unknown) =\u003e {\n        throw new Error(\"Unexpected value: \" + value);\n    }\n]);\n\n// Transpiles to:\nconst toNumber = value_1 =\u003e {\n    if (typeof value_1 === \"boolean\") return +value_1;\n    else if (typeof value_1 === \"string\") return +value_1;\n    else if (typeof value_1 === \"number\") return value_1;\n    else if (Array.isArray(value_1)) {\n        if (value_1.every(value_2 =\u003e typeof value_2 === \"string\") || value_1.every(value_3 =\u003e typeof value_3 === \"number\") || value_1.every(value_4 =\u003e typeof value_4 === \"boolean\"))\n            return value_1.map(v =\u003e toNumber(v)).reduce((val, acc) =\u003e val + acc, 0);\n    }\n    throw new Error(\"Unexpected value: \" + value_1);\n};\n```\n\nIf the `discriminatedObjAssert` parameter is set to true, then if you have a discriminated object (object which has a literal property), only the literal property will be validated. Use this if you have already validated the source or if you know that it's correct.\n\n### Destructuring\n\nIf a value is a destructured object / array, then only the deconstructed properties / elements will get validated.\n\n```ts\nfunction test({\n    user: {\n        skills: [skill1, skill2, skill3]\n    }\n}: Assert\u003c\n    {\n        user: {\n            username: string;\n            password: string;\n            skills: [string, string?, string?];\n        };\n    },\n    undefined\n\u003e) {\n    // Your code\n}\n\n// Transpiles to:\nfunction test({\n    user: {\n        skills: [skill1, skill2, skill3]\n    }\n}) {\n    if (typeof skill1 !== \"string\") return undefined;\n    if (skill2 !== undefined \u0026\u0026 typeof skill2 !== \"string\") return undefined;\n    if (skill3 !== undefined \u0026\u0026 typeof skill3 !== \"string\") return undefined;\n}\n```\n\n### Supported types and code generation\n\n-   `string`s and string literals\n    -   `typeof value === \"string\"` or `value === \"literal\"`\n-   `number`s and number literals\n    -   `typeof value === \"number\"` or `value === 420`\n-   `boolean`\n    -   `value === true || value === false`\n-   `symbol`\n    -   `typeof value === \"symbol\"`\n-   `bigint`\n    -   `typeof value === \"bigint\"`\n-   `null`\n    -   `value === null`\n-   `undefined`\n    -   `value === undefined`\n-   Tuples (`[a, b, c]`)\n    -   `Array.isArray(value)`\n    -   Each type in the tuple gets checked individually.\n-   Arrays (`Array\u003ca\u003e`, `a[]`)\n    -   `Array.isArray(value)`\n    -   Each value in the array gets checked via a `for` loop.\n-   Interfaces and object literals (`{a: b, c: d}`)\n    -   `typeof value === \"object\"`\n    -   `value !== null`\n    -   Each property in the object gets checked individually.\n-   Classes\n    -   `value instanceof Class`\n-   Enums\n-   Unions (`a | b | c`)\n    -   Discriminated unions - Each type in the union must have a value that's either a string or a number literal.\n-   Function type parameters\n    -   Inside the function as one big union with the `Infer` utility type.\n    -   At the call site of the function with the `Resolve` utility type.\n-   Recursive types\n    -   A function gets generated for recursive types, with the validation code inside.\n    -   **Note:** Currently, because of limitations, errors in recursive types are a lot more limited.\n\n### Complex types\n\nMarkers **can** be used in type aliases, so you can easily create shortcuts to common patterns:\n\n**Combining checks:**\n\n```ts\n// Combining all number related checks into one type\ntype Num\u003cmin extends number | undefined = undefined, max extends number | undefined = undefined, typ extends Int | Float | undefined = undefined\u003e = number \u0026\n    (min extends number ? Min\u003cmin\u003e : number) \u0026\n    (max extends number ? Max\u003cmax\u003e : number) \u0026\n    (typ extends undefined ? number : typ);\n\nfunction verify(n: Assert\u003cNum\u003c2, 10, Int\u003e\u003e) {\n    // ...\n}\n\n// Transpiles to:\nfunction verify(n) {\n    if (typeof n !== \"number\" || n \u003c 2 || n \u003e 10 || n % 1 !== 0) throw new Error(\"Expected n to be a number, to be greater than 2, to be less than 10, to be an int\");\n}\n```\n\n### Transformer options\n\n#### JSON Schema \n\nThe transformer allows you to turn any of the types you use in your project into [JSON Schemas](https://json-schema.org/) with the `jsonSchema` configuration option:\n\n```js\n\"compilerOptions\": {\n//... other options\n\"plugins\": [\n        {\n            \"transform\": \"ts-runtime-checks\",\n            \"jsonSchema\": {\n                \"dist\": \"./schemas\"\n            }\n        }\n    ]\n}\n```\n\nUsing the configuration above, all types in your project will be turned into JSON Schemas and be saved in the `./schemas` directory, each one in different file. You can also filter types by using either the `types` option or the `typePrefix` option:\n\n```js\n\"jsonSchema\": {\n    \"dist\": \"./schemas\",\n    // Only specific types will be turned to schemas\n    \"types\": [\"User\", \"Member\", \"Guild\"],\n    // Only types with names that start with a specific prefix will be turned to schemas\n    \"typePrefix\": \"$\"\n}\n```\n\n#### `assertAll`\n\nSetting this option to true will add assertion code to ALL function parameters and `as` assertions. The assertion code will throw an error. You can use the `NoCheck` marker to override this behaviour.\n\n## Contributing\n\n`ts-runtime-checks` is being maintained by a single person. Contributions are welcome and appreciated. Feel free to open an issue or create a pull request at https://github.com/GoogleFeud/ts-runtime-checks\n","funding_links":[],"categories":["TypeScript","Packages"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FGoogleFeud%2Fts-runtime-checks","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FGoogleFeud%2Fts-runtime-checks","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FGoogleFeud%2Fts-runtime-checks/lists"}