{"id":31989368,"url":"https://github.com/nyaomaru/is-kit","last_synced_at":"2026-05-09T07:12:42.116Z","repository":{"id":318137477,"uuid":"1067760372","full_name":"nyaomaru/is-kit","owner":"nyaomaru","description":"Lightweight, zero-dependency toolkit for building `isFoo` style type guards in TypeScript. Runtime-safe 🛡️, composable 🧩, and ergonomic ✨. npm -\u003e https://www.npmjs.com/package/is-kit","archived":false,"fork":false,"pushed_at":"2026-04-25T07:25:49.000Z","size":789,"stargazers_count":36,"open_issues_count":2,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-04-25T08:37:52.916Z","etag":null,"topics":["is","is-kit","open-source","runtime-type-checking","type-guard","type-guards","type-safe","typescript","utility","validation"],"latest_commit_sha":null,"homepage":"https://is-kit-docs.vercel.app","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/nyaomaru.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2025-10-01T10:54:11.000Z","updated_at":"2026-04-25T07:25:02.000Z","dependencies_parsed_at":"2025-10-05T11:51:43.453Z","dependency_job_id":null,"html_url":"https://github.com/nyaomaru/is-kit","commit_stats":null,"previous_names":["nyaomaru/is-kit"],"tags_count":33,"template":false,"template_full_name":null,"purl":"pkg:github/nyaomaru/is-kit","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nyaomaru%2Fis-kit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nyaomaru%2Fis-kit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nyaomaru%2Fis-kit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nyaomaru%2Fis-kit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nyaomaru","download_url":"https://codeload.github.com/nyaomaru/is-kit/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nyaomaru%2Fis-kit/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32810469,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-08T08:22:46.396Z","status":"online","status_checked_at":"2026-05-09T02:00:06.633Z","response_time":123,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["is","is-kit","open-source","runtime-type-checking","type-guard","type-guards","type-safe","typescript","utility","validation"],"created_at":"2025-10-15T10:49:57.639Z","updated_at":"2026-05-09T07:12:42.103Z","avatar_url":"https://github.com/nyaomaru.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# is-kit\n\n\u003cp align=\"center\"\u003e\n  \u003cimg\n    src=\"https://raw.githubusercontent.com/nyaomaru/is-kit/main/docs/public/iskit_image.png\"\n    width=\"600\"\n    alt=\"is-kit logo\"\n  /\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://www.npmjs.com/package/is-kit\"\u003e\n    \u003cimg src=\"https://img.shields.io/npm/v/is-kit.svg\" alt=\"npm version\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://jsr.io/@nyaomaru/is-kit\"\u003e\n    \u003cimg src=\"https://img.shields.io/jsr/v/@nyaomaru/is-kit\" alt=\"JSR\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://www.npmjs.com/package/is-kit\"\u003e\n    \u003cimg src=\"https://img.shields.io/npm/dt/is-kit.svg\" alt=\"npm downloads\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/nyaomaru/is-kit/blob/main/LICENSE\"\u003e\n    \u003cimg src=\"https://img.shields.io/npm/l/is-kit.svg?sanitize=true\" alt=\"License\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n`is-kit` is a lightweight, zero-dependency toolkit for building reusable TypeScript **type guards**.\n\nIt helps you write small `isFoo` functions, compose them into **richer runtime checks**, and keep **TypeScript narrowing** natural inside regular control flow.\n\n**Runtime-safe** 🛡️, **composable** 🧩, and **ergonomic** ✨ without asking you to adopt a heavy schema workflow.\n\n- Build and reuse **typed guards**\n- **Compose guards** with `and`, `or`, `not`, `oneOf`\n- **Validate object** shapes and collections\n- **Parse or assert** `unknown` values without a large schema framework\n\n[📚 Documentation Site](https://is-kit-docs.vercel.app/)\n\n\u003e Best for **app-internal narrowing, filtering, and reusable guards**.\n\n## 🤔 Why use `is-kit`?\n\nTired of rewriting the same `isFoo` checks again and again?\n\n`is-kit` is a good fit when you want to:\n\n- **write reusable `isX`** functions instead of one-off inline checks\n- keep runtime validation **lightweight and dependency-free**\n- **narrow values directly** in `if`, `filter`, and other TypeScript control flow\n- **compose validation logic** from small guards instead of large schema objects\n\n`is-kit` is probably not the best first choice if you mainly want:\n\n- rich, structured validation errors\n- schema-first workflows\n- data transformation pipelines\n\nIn those cases, a schema validator such as `Zod` may be a better fit. (Of course, you can combine them 🍲)\n\n`is-kit` is meant to take the boring part out of writing guards, while still feeling like normal TypeScript.\n\n\u003e Grab a coffee ☕ and let `is-kit` handle the repetitive part.\n\n## 📥 Install\n\n```bash\npnpm add is-kit\n# or\nbun add is-kit\n# or\nnpm install is-kit\n# or\nyarn add is-kit\n```\n\nESM and CJS builds are available for npm consumers, and bundled types are included.\n\n### JSR\n\n```ts\nimport { and, define, or } from 'jsr:@nyaomaru/is-kit';\n```\n\n## ✨ Quick Start\n\nStart with a plain object guard and parse an `unknown` value.\n\n```ts\nimport { isNumber, isString, optionalKey, safeParse, struct } from 'is-kit';\n\ndeclare const input: unknown;\n\nconst isUser = struct({\n  id: isNumber,\n  name: isString,\n  nickname: optionalKey(isString)\n});\n\nconst result = safeParse(isUser, input);\n\nif (result.valid) {\n  result.value.id;\n  result.value.name;\n  result.value.nickname?.toUpperCase();\n}\n```\n\nThis is the core idea of `is-kit`:\n\n1. Build small guards.\n2. Compose them.\n3. Reuse them anywhere TypeScript narrowing matters.\n\n## ⌚ A 30-second Mental Model\n\nIf you are new to the library, these are the pieces to remember:\n\n- `define\u003cT\u003e(fn)` turns a boolean check into a typed guard.\n- `predicateToRefine(fn)` upgrades an existing predicate so it can participate in narrowing chains.\n- `struct({...})` builds an object-shape guard.\n- `safeParse(guard, value)` gives you a small tagged result object.\n- `assert(guard, value)` throws if the value does not match.\n\n## ⚒️ Common Usage\n\n### 1. Create a custom guard\n\nUse `define` when you already know the runtime condition you want.\n\n```ts\nimport { define, isString } from 'is-kit';\n\nconst isShortString = define\u003cstring\u003e(\n  (value) =\u003e isString(value) \u0026\u0026 value.length \u003c= 3\n);\n```\n\n### 2. Add refinements to an existing guard\n\nUse `and` plus `predicateToRefine` when you want a broad guard first and a narrower condition after that.\n\n```ts\nimport { and, isNumber, predicateToRefine } from 'is-kit';\n\nconst isPositiveNumber = and(\n  isNumber,\n  predicateToRefine\u003cnumber\u003e((value) =\u003e value \u003e 0)\n);\n```\n\n### 3. Compose multiple guards\n\nUse `or` and `oneOf` to combine smaller guards into readable predicates.\n\n```ts\nimport { oneOf, or, isBoolean, isNumber, isString } from 'is-kit';\n\nconst isStringOrNumber = or(isString, isNumber);\nconst isScalar = oneOf(isString, isNumber, isBoolean);\n```\n\nUse `not(...)` when you want the complement of an existing guard or refinement.\n\n### 4. Validate object shapes\n\nUse `struct` for plain-object payloads. Keys are required by default.\n\n```ts\nimport { isNumber, isString, optional, optionalKey, struct } from 'is-kit';\n\nconst isProfile = struct(\n  {\n    id: isNumber,\n    name: isString,\n    bio: optionalKey(isString)\n  },\n  { exact: true }\n);\n\nconst isConfig = struct({\n  label: isString,\n  subtitle: optional(isString),\n  note: optionalKey(optional(isString))\n});\n```\n\n`optionalKey(guard)` means the property may be missing.\n\nUse `struct(schema, { exact: true })` when extra keys should be rejected.\n\nIf the property must exist but the value may be `undefined`, use `optional(guard)` instead.\n\n### 5. Validate arrays, tuples, maps, sets, and records\n\nCollection combinators keep your element guards reusable.\n\n```ts\nimport {\n  arrayOf,\n  isNumber,\n  isString,\n  mapOf,\n  nonEmptyArrayOf,\n  recordOf,\n  setOf,\n  tupleOf\n} from 'is-kit';\n\nconst isStringArray = arrayOf(isString);\nconst isNonEmptyTagList = nonEmptyArrayOf(isString);\nconst isPoint = tupleOf(isNumber, isNumber);\nconst isTagSet = setOf(isString);\nconst isScoreMap = mapOf(isString, isNumber);\nconst isStringRecord = recordOf(isString, isString);\n```\n\nUse `oneOfValues` for unions of literal primitives.\n\n```ts\nimport { oneOfValues } from 'is-kit';\n\nconst isStatus = oneOfValues('draft', 'published', 'archived');\n```\n\n### 6. Handle null and undefined explicitly\n\nUse the nullish helpers to say exactly what is allowed.\n\n```ts\nimport {\n  isString,\n  nonNull,\n  nullable,\n  nullish,\n  optional,\n  required\n} from 'is-kit';\n\nconst isNullableString = nullable(isString);\nconst isNullishString = nullish(isString);\nconst isOptionalString = optional(isString);\nconst isDefinedString = required(optional(isString));\nconst isNonNullString = nonNull(nullable(isString));\n```\n\n### 7. Parse or assert unknown input\n\nUse `safeParse` when you want a result object, and `assert` when invalid data should stop execution.\n\n```ts\nimport { assert, isString, safeParse } from 'is-kit';\n\ndeclare const input: unknown;\n\nconst parsed = safeParse(isString, input);\n\nif (parsed.valid) {\n  parsed.value.toUpperCase();\n}\n\nassert(isString, input, 'Expected a string');\ninput.toUpperCase();\n```\n\n### 8. Narrow object keys\n\nUse key helpers when the important part of a value is one property.\n\n```ts\nimport {\n  hasKey,\n  hasKeys,\n  isNumber,\n  isString,\n  narrowKeyTo,\n  oneOfValues,\n  struct\n} from 'is-kit';\n\nconst isUser = struct({\n  id: isNumber,\n  name: isString,\n  role: oneOfValues('admin', 'member', 'guest')\n});\n\nconst hasRole = hasKey('role');\nconst hasRoleAndId = hasKeys('role', 'id');\nconst byRole = narrowKeyTo(isUser, 'role');\nconst isAdmin = byRole('admin');\n\nconst value: unknown = { id: 1, name: 'nyaomaru', role: 'admin' };\n\nif (hasRole(value)) {\n  value.role;\n}\n\nif (hasRoleAndId(value)) {\n  value.role;\n  value.id;\n}\n\nif (isAdmin(value)) {\n  value.role;\n  value.name;\n}\n```\n\n## 🌍 Real-world use cases\n\nHere are the kinds of problems `is-kit` is especially good at solving:\n\n### API response checks\n\n```ts\nimport { isNumber, isString, safeParse, struct } from 'is-kit';\n\nconst isPost = struct({\n  id: isNumber,\n  title: isString\n});\n\nconst parsed = safeParse(isPost, payload);\nif (parsed.valid) {\n  renderPost(parsed.value);\n}\n```\n\n### Safe array filtering\n\n```ts\nimport { isNumber } from 'is-kit';\n\nconst values: unknown[] = [1, 'two', 3];\nconst numbers = values.filter(isNumber);\n```\n\n### Narrowing by discriminant\n\n```ts\nimport { isNumber, isString, narrowKeyTo, oneOfValues, struct } from 'is-kit';\n\nconst isEvent = struct({\n  type: oneOfValues('click', 'submit'),\n  label: isString,\n  timestamp: isNumber\n});\n\nconst byType = narrowKeyTo(isEvent, 'type');\nconst isSubmitEvent = byType('submit');\n```\n\n## 🎯 API Overview\n\nThe library is organized around a few small building blocks:\n\n- **Primitives**: `isString`, `isNumber`, `isBoolean`, `isInteger`, ...\n- **Composition**: `define`, `and`, `andAll`, `or`, `not`, `oneOf`\n- **Object shapes**: `struct`, `optionalKey`, `hasKey`, `hasKeys`, `narrowKeyTo`\n- **Collections**: `arrayOf`, `nonEmptyArrayOf`, `tupleOf`, `setOf`, `mapOf`, `recordOf`\n- **Literals**: `oneOfValues`, `equals`, `equalsBy`, `equalsKey`\n- **Nullish handling**: `nullable`, `nonNull`, `nullish`, `optional`, `required`\n- **Result helpers**: `safeParse`, `safeParseWith`, `assert`\n\nFor the full API list and dedicated pages, use the docs site below.\n\n## 📚 Full Documentation\n\nFor detailed API pages and more examples, see:\n\nhttps://is-kit-docs.vercel.app/\n\n## 👨‍💻 Development\n\nRequires Node 22 and pnpm 10.12.4.\n\n- `pnpm lint`\n- `pnpm build`\n- `pnpm test`\n- `pnpm test:types`\n\nSee `DEVELOPER.md` for setup details and `CONTRIBUTE.md` for contribution workflow.\n\nPick a guard, compose it, and ship with confidence 🚀\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnyaomaru%2Fis-kit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnyaomaru%2Fis-kit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnyaomaru%2Fis-kit/lists"}