{"id":21482380,"url":"https://github.com/topgunbuild/typed","last_synced_at":"2025-07-03T01:38:05.516Z","repository":{"id":158795491,"uuid":"633716847","full_name":"TopGunBuild/typed","owner":"TopGunBuild","description":"Type checking and type-safe runtime validation library","archived":false,"fork":false,"pushed_at":"2023-08-23T07:58:14.000Z","size":294,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-28T09:18:03.723Z","etag":null,"topics":["interface","schema","struct","types","typescript","validation"],"latest_commit_sha":null,"homepage":"","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/TopGunBuild.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2023-04-28T05:59:38.000Z","updated_at":"2023-08-21T17:00:50.000Z","dependencies_parsed_at":"2023-09-21T20:40:01.799Z","dependency_job_id":"243cb6a9-1cfc-4a2c-aa17-c4f4625bb4c0","html_url":"https://github.com/TopGunBuild/typed","commit_stats":null,"previous_names":["topgunbuild/typed","topgunbuild/topgun-typed"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/TopGunBuild/typed","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TopGunBuild%2Ftyped","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TopGunBuild%2Ftyped/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TopGunBuild%2Ftyped/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TopGunBuild%2Ftyped/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TopGunBuild","download_url":"https://codeload.github.com/TopGunBuild/typed/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TopGunBuild%2Ftyped/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262417011,"owners_count":23307796,"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":["interface","schema","struct","types","typescript","validation"],"created_at":"2024-11-23T12:32:52.124Z","updated_at":"2025-07-03T01:38:05.481Z","avatar_url":"https://github.com/TopGunBuild.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\" style=\"border-bottom: none;\"\u003e✅ @topgunbuild/typed\u003c/h1\u003e\n\u003ch3 align=\"center\"\u003eFast, tiny and type-safe runtime validation library for \u003ca href=\"https://github.com/TopGunBuild/topgun\"\u003eTopGun\u003c/a\u003e\u003c/h3\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://npm.im/@topgunbuild/typed\"\u003e\n    \u003cimg alt=\"npm\" src=\"https://badgen.net/npm/v/@topgunbuild/typed\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://bundlephobia.com/result?p=@topgunbuild/typed\"\u003e\n    \u003cimg alt=\"bundlephobia\" src=\"https://img.shields.io/bundlephobia/minzip/@topgunbuild/typed.svg\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://opensource.org/licenses/MIT\"\u003e\n      \u003cimg alt=\"License: MIT\" src=\"https://img.shields.io/badge/License-MIT-yellow.svg\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n## Install\n\n```bash\nnpm install @topgunbuild/typed\n```\n\n## Usage\n\n```ts\nimport * as t from \"@topgunbuild/typed\";\n\nconst post = t.object({\n  id: t.number(),\n  title: t.string(),\n});\n\nconst postList = t.array(post);\n\n// Get the actual type of the postList\ntype PostList = t.Infer\u003ctypeof postList\u003e;\n\n// Some json data from somewhere\nconst data = {} as any;\n\nconst result = postList(data);\n\nif (result.ok) {\n  // Do something with the data\n  result.data;\n} else {\n  // Handle the error\n  result.error;\n}\n\n// Or you can just unwrap the value directly. It will throw if the data is invalid.\nconst parsed = t.unwrap(result);\n\n// Or if you don't want it to throw, you can use `unwrapOr`\nconst parsed = t.unwrapOr(result, {\n  /* a default value */\n});\n```\n\n### Fetch example\n\nValidate data from a remote API.\n\n```ts\nimport * as t from \"@topgunbuild/typed\";\n\nconst post = t.object({\n  id: t.number(),\n  title: t.string(),\n});\n\nconst postList = t.array(post);\n\n// If everything goes ok, posts will be correctly typed as `Post[]`.\n// If not, an error will be thrown.\nconst posts = await fetch(\"https://jsonplaceholder.typicode.com/posts\")\n  .then((res) =\u003e res.json())\n  .then(postList)\n  .then(t.unwrap);\n```\n\n## Custom Types\n\nThere's a chance you'll want to define more complex types to deal with your data. You can do this in a few ways:\n\n- Using the `map` function.\n- Using the `chain` function.\n- Creating a struct from scratch.\n\n### Using the `map` function\n\nThe map function allows you to convert one \"base\" type into another. It always starts from a base type.\n\n```ts\nimport * as t from \"@topgunbuild/typed\";\n\n// Suppose we have this geolocation struct.\nconst latLng = t.object({\n  lat: t.number(),\n  lng: t.number(),\n});\n\n// `asNumber` means we can pass a string and it will be converted to a number.\nconst latLngPair = t.tuple([t.asNumber(), t.asNumber()]);\n\n// And we'd like to have a type that takes a string a returns a `LatLng`.\nconst asLatLng = t.map(t.string(), (str) =\u003e {\n  // Here `str` is guaranteed to be a string.\n\n  // Here we validate our splited string against a tuple of two numbers.\n  const result = latLngPair(str.split(\",\"));\n\n  // If it succeeds we return a `LatLng` struct. If not, forwards the error.\n  return t.isOk(result) ? latLng(result.data) : result;\n});\n\n// Now we can use `asLatLng` to validate a string.\nconst str = \"42.123,42.123\";\n\nconst result = asLatLng(str); // `result` will be a `LatLng` struct.\n```\n\n### Using the `chain` function\n\nThe `chain` function is useful when you don't want to change the type of your data, but further process it.\n\nFor example, if you have a string that you want to trim and lowercase it, then `chain` is the function you want to use.\n\n```ts\nimport * as t from \"@topgunbuild/typed\";\n\nconst trim = (value: string) =\u003e value.trim();\nconst lower = (value: string) =\u003e value.toLowerCase();\n\nconst trimLower = t.chain(\n  t.string(),\n  trim,\n  lower /* whatever else function you want as longs as it at takes the same type and returns the same type */,\n);\n\nconst result = trimLower(\"  Hello World  \"); // { ok: true, value: \"hello world\" }\n```\n\n### Creating a struct from scratch\n\nA struct is nothing more than a function that takes whatever input and returns a `Result`. The convention in `@topgunbuild/typed` is to have factory functions that return a struct just to be able to customize error messages. This was not the case in previous versions of typed, but it is now.\n\n```ts\nimport * as t from \"@topgunbuild/typed\";\n\nconst regex =\n  (regex: RegExp, msg = \"Expecting value to match regex\"): t.Struct\u003cstring\u003e =\u003e\n  (input) =\u003e {\n    if (typeof input !== \"string\" || !regex.test(input)) {\n      return t.err(new t.StructError(msg, { input }));\n    }\n    return t.ok(input);\n  };\n```\n\n_You can browse the `@topgunbuild/typed` source code to see how structs are implemented if you're curious._\n\n## Notes\n\n`@topgunbuild/typed` will deep clone non primitive values as it validates them. So if you pass an object or array to a struct, it will be cloned. This is to say that `@topgunbuild/typed` will get rid of any extra properties on your data, so it'll exactly match the shape you defined.\n\n## Reference\n\nThe code in this repository is based on `typed` (https://github.com/brielov/typed).\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftopgunbuild%2Ftyped","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftopgunbuild%2Ftyped","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftopgunbuild%2Ftyped/lists"}