{"_id":"@epic-web/invariant","_rev":"4115703","name":"@epic-web/invariant","description":"Type safe utilities for throwing errors (and responses) if things aren't quite right. Inspired by npm.im/invariant","dist-tags":{"latest":"1.0.0"},"maintainers":[{"name":"epic-web-bot","email":""},{"name":"kentcdodds","email":"kent+npm@doddsfamily.us"},{"name":"kettanaito","email":""}],"time":{"modified":"2026-02-12T21:48:40.000Z","created":"2023-12-14T00:28:05.418Z","1.0.0":"2023-12-14T00:28:05.418Z"},"users":{},"author":{"name":"Kent C. Dodds","email":"me@kentcdodds.com","url":"https://kentcdodds.com/"},"repository":{"type":"git","url":"git+https://github.com/epicweb-dev/invariant.git"},"versions":{"1.0.0":{"name":"@epic-web/invariant","version":"1.0.0","description":"Type safe utilities for throwing errors (and responses) if things aren't quite right. Inspired by npm.im/invariant","publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/epicweb-dev/invariant.git"},"bugs":{"url":"https://github.com/epicweb-dev/invariant/issues"},"homepage":"https://github.com/epicweb-dev/invariant#readme","type":"module","main":"./dist/index.js","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"scripts":{"build":"tsc","format":"prettier --write .","test":"tsx --test --test-reporter spec --experimental-test-coverage test/*.test.ts","test:watch":"tsx --test --test-reporter spec --watch test/*.test.ts"},"devDependencies":{"@types/node":"^20.10.4","prettier":"^3.1.1","tsx":"^4.6.2","typescript":"^5.3.3"},"prettier":{"semi":false,"useTabs":true,"singleQuote":true,"proseWrap":"always","overrides":[{"files":["**/*.json"],"options":{"useTabs":false}}]},"keywords":[],"author":{"name":"Kent C. Dodds","email":"me@kentcdodds.com","url":"https://kentcdodds.com/"},"license":"MIT","_id":"@epic-web/invariant@1.0.0","gitHead":"547be2246d3c39f8ca44dd0502b1aa70bf4378af","types":"./dist/index.d.ts","_nodeVersion":"20.10.0","_npmVersion":"10.2.3","dist":{"shasum":"1073e5dee6dd540410784990eb73e4acd25c9813","size":3599,"noattachment":false,"key":"/@epic-web/invariant/-/@epic-web/invariant-1.0.0.tgz","tarball":"http://registry.cnpm.dingdandao.com/@epic-web/invariant/download/@epic-web/invariant-1.0.0.tgz"},"_npmUser":{"name":"epic-web-bot","email":"me+epic-web-bot@kentcdodds.com"},"directories":{},"maintainers":[{"name":"epic-web-bot","email":""},{"name":"kentcdodds","email":"kent+npm@doddsfamily.us"},{"name":"kettanaito","email":""}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/invariant_1.0.0_1702513685231_0.3391591949460089"},"_hasShrinkwrap":false,"_cnpmcore_publish_time":"2023-12-14T00:28:05.418Z","publish_time":1702513685418,"_source_registry_name":"default","_cnpm_publish_time":1702513685418}},"readme":"<div>\n\t<h1 align=\"center\"><a href=\"https://npm.im/@epic-web/invariant\">???? @epic-web/invariant</a></h1>\n\t<strong>\n\t\tThrow errors when thing's aren't right.\n\t</strong>\n\t<p>\n\t\tType safe utilities for throwing errors (and responses) in exceptional\n\t\tsituations in a declarative way.\n\t</p>\n</div>\n\n```\nnpm install @epic-web/invariant\n```\n\n<div align=\"center\">\n\t<a\n\t\talt=\"Epic Web logo\"\n\t\thref=\"https://www.epicweb.dev\"\n\t>\n\t\t<img\n\t\t\twidth=\"300px\"\n\t\t\tsrc=\"https://github-production-user-asset-6210df.s3.amazonaws.com/1500684/257881576-fd66040b-679f-4f25-b0d0-ab886a14909a.png\"\n\t\t/>\n\t</a>\n</div>\n\n<hr />\n\n<!-- prettier-ignore-start -->\n[![Build Status][build-badge]][build]\n[![MIT License][license-badge]][license]\n[![Code of Conduct][coc-badge]][coc]\n<!-- prettier-ignore-end -->\n\n## The Problem\n\nYour application has boundaries. Network requests/responses, file system reads,\netc. When you're working with these boundaries, you need to be able to handle\nerrors that may occur, even in TypeScript.\n\nTypeScript will typically make these boundaries much more obvious because it\ndoesn't like not knowing what the type of something is. For example:\n\n```ts\nconst formData = new FormData(formElement)\nconst name = await formData.get('name')\n// name is `File | string | null`\n```\n\nOften it's a good idea to use a proper parsing library for situations like this,\nbut for simple cases that can often feel like overkill. But you don't want to\njust ignore TypeScript because:\n\n> TypeScript is that brutally honest friend you put up with because they save\n> you from making terrible mistakes. –\n> [@kentcdodds](https://twitter.com/kentcdodds/status/1715562350835855396)\n\nSo you check it:\n\n```ts\nconst formData = new FormData(formElement)\nconst name = await formData.get('name')\n// name is `File | string | null`\nif (typeof name !== 'string') {\n\tthrow new Error('Name must be a string')\n}\n// now name is `string` (and TypeScript knows it too)\n```\n\nYou're fine throwing a descriptive error here because it's just _very_ unlikely\nthis will ever happen and even if it does you wouldn't really know what to do\nabout it anyway.\n\nIt's not a big deal, but there's a tiny bit of boilerplate that would be nice to\navoid. Especially when you find yourself doing this all over the codebase. This\nis the problem `@epic-web/invariant` solves.\n\n## The Solution\n\nHere's the diff from what we had above:\n\n```diff\nconst formData = new FormData(formElement)\nconst name = await formData.get('name')\n// name is `File | string | null`\n- if (typeof name !== 'string') {\n- \tthrow new Error('Name must be a string')\n- }\n+ invariant(typeof name === 'string', 'Name must be a string')\n// now name is `string` (and TypeScript knows it too)\n```\n\nIt's pretty simple. But honestly, it's nicer to read, it throws a special\n`InvariantError` object to distinguish it from other types of errors, and we\nhave another useful utility for throwing `Response` objects instead of `Error`\nobjects which is handy\n[in Remix](https://remix.run/docs/en/main/route/loader#throwing-responses-in-loaders).\n\n## Usage\n\n### `invariant`\n\nThe `invariant` function is used to assert that a condition is true. If the\ncondition is false, it throws an error with the provided message.\n\n**Basic Usage**\n\n```ts\nimport { invariant } from '@epic-web/invariant'\n\nconst creature = { name: 'Dragon', type: 'Fire' }\ninvariant(creature.name === 'Dragon', 'Creature must be a Dragon')\n```\n\n**Throwing a Response on False Condition**\n\n```ts\nimport { invariant } from '@epic-web/invariant'\n\nconst creature = { name: 'Unicorn', type: 'Magic' }\ninvariant(creature.type === 'Fire', 'Creature must be of type Fire')\n// Throws: InvariantError: Creature must be of type Fire\n```\n\n**Using Callback for Error Message**\n\n```ts\nimport { invariantResponse } from '@epic-web/invariant'\n\nconst creature = { name: 'Elf', type: 'Forest' }\ninvariant(creature.type === 'Water', () => 'Creature must be of type Water')\n// Throws: InvariantError: Creature must be of type Water\n```\n\n### `invariantResponse`\n\nThe `invariantResponse` function works similarly to `invariant`, but instead of\nthrowing an `InvariantError`, it throws a Response object.\n\n**Basic Usage**\n\n```ts\nimport { invariantResponse } from '@epic-web/invariant'\n\nconst creature = { name: 'Phoenix', type: 'Fire' }\ninvariantResponse(creature.type === 'Fire', 'Creature must be of type Fire')\n```\n\n**Throwing a Response on False Condition**\n\n```ts\nimport { invariantResponse } from '@epic-web/invariant'\n\nconst creature = { name: 'Griffin', type: 'Air' }\ninvariantResponse(creature.type === 'Water', 'Creature must be of type Water')\n// Throws: Response { status: 400, body: 'Creature must be of type Water' }\n```\n\nThe response status default if 400 (Bad Request), but you'll find how to change\nthat below.\n\n**Using Callback for Response Message**\n\n```ts\nimport { invariantResponse } from '@epic-web/invariant'\n\nconst creature = { name: 'Mermaid', type: 'Water' }\ninvariantResponse(\n\tcreature.type === 'Land',\n\t() => `Expected a Land creature, but got a ${creature.type} creature`,\n)\n```\n\n**Throwing a Response with Additional Options**\n\n```ts\nimport { invariantResponse } from '@epic-web/invariant'\n\nconst creature = { name: 'Cerberus', type: 'Underworld' }\ninvariantResponse(\n\tcreature.type === 'Sky',\n\tJSON.stringify({ error: 'Creature must be of type Sky' }),\n\t{ status: 500, headers: { 'Content-Type': 'text/json' } },\n)\n```\n\n## Differences from [invariant](https://www.npmjs.com/package/invariant)\n\nThere are three main differences. With `@epic-web/invariant`:\n\n1. Error messages are the same in dev and prod\n2. It's typesafe\n3. We support the common case (for Remix anyway) of throwing Responses as well\n   with `invariantResponse`.\n\n## License\n\nMIT\n\n<!-- prettier-ignore-start -->\n[build-badge]: https://img.shields.io/github/actions/workflow/status/epicweb-dev/invariant/release.yml?branch=main&logo=github&style=flat-square\n[build]: https://github.com/epicweb-dev/invariant/actions?query=workflow%3Arelease\n[license-badge]: https://img.shields.io/badge/license-MIT%20License-blue.svg?style=flat-square\n[license]: https://github.com/epicweb-dev/invariant/blob/main/LICENSE\n[coc-badge]: https://img.shields.io/badge/code%20of-conduct-ff69b4.svg?style=flat-square\n[coc]: https://kentcdodds.com/conduct\n<!-- prettier-ignore-end -->\n","_attachments":{},"homepage":"https://github.com/epicweb-dev/invariant#readme","bugs":{"url":"https://github.com/epicweb-dev/invariant/issues"},"license":"MIT"}