{"id":20327062,"url":"https://github.com/webneat/wari","last_synced_at":"2025-04-11T20:07:16.362Z","repository":{"id":188136360,"uuid":"678043686","full_name":"webNeat/wari","owner":"webNeat","description":"A type-safe way to create and handle errors.","archived":false,"fork":false,"pushed_at":"2024-11-30T17:34:10.000Z","size":132,"stargazers_count":12,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-10T15:09:42.363Z","etag":null,"topics":["error-handling","error-management","error-maping","throw","try-catch","type-safety","typesafe","typescript"],"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/webNeat.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-08-13T13:56:41.000Z","updated_at":"2024-11-30T17:33:55.000Z","dependencies_parsed_at":null,"dependency_job_id":"29bac459-6da3-45a2-87dd-806636700731","html_url":"https://github.com/webNeat/wari","commit_stats":null,"previous_names":["webneat/wari"],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webNeat%2Fwari","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webNeat%2Fwari/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webNeat%2Fwari/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webNeat%2Fwari/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/webNeat","download_url":"https://codeload.github.com/webNeat/wari/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248290460,"owners_count":21078992,"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":["error-handling","error-management","error-maping","throw","try-catch","type-safety","typesafe","typescript"],"created_at":"2024-11-14T19:46:25.601Z","updated_at":"2025-04-11T20:07:16.352Z","avatar_url":"https://github.com/webNeat.png","language":"TypeScript","readme":"# wari\n\nA type-safe way to create and handle errors in TypeScript.\n\n[![Bundle size](https://img.shields.io/bundlephobia/minzip/wari?style=flat-square)](https://bundlephobia.com/result?p=wari)\n[![Version](https://img.shields.io/npm/v/wari?style=flat-square)](https://www.npmjs.com/package/wari)\n[![Tests Status](https://img.shields.io/github/actions/workflow/status/webneat/wari/tests.yml?branch=main\u0026style=flat-square)](https://github.com/webneat/wari/actions?query=workflow:\"Tests\")\n[![MIT License](https://img.shields.io/npm/l/wari?style=flat-square)](LICENSE)\n\n# Contents\n\n- [Introduction](#introduction)\n- [Installation](#installation)\n- [Getting Started](#getting-started)\n  - [Defining Error Types](#defining-error-types)\n  - [Creating Errors](#creating-errors)\n  - [Handling Errors](#handling-errors)\n  - [Catching External Errors](#catching-external-errors)\n  - [Creating Safe Functions](#creating-safe-functions)\n- [Contributing](#contributing)\n- [Changelog](#changelog)\n\n# Introduction\n\n**wari** is a TypeScript library that provides a type-safe way to create and handle errors. It allows you to define custom error types and handle them using pattern matching, without the need to create custom error classes or use `instanceof` checks.\n\n## Why Use wari?\n\n**wari** simplifies error handling by:\n\n- Allowing you to define **error types** without creating new classes.\n- Providing **type-safe functions** to create and handle errors.\n- Enabling **pattern matching** on errors for cleaner and more maintainable code.\n\n# Get started with `wari`\n\n## Installation\n\nStart by installing the library\n\n```bash\nnpm install wari\n# or\nyarn add wari\n# or\npnpm add wari\n```\n\n## Defining Error Types\n\n`wari` exports the interface `ErrorTypes` which can used to add new error types as follows:\n\n```ts\ndeclare module 'wari' {\n  interface ErrorTypes {\n    'HttpError': {method: 'GET' | 'POST', url: string, status: number}\n    'JsonError': {text: string}\n    'FileError': {operation: 'read' | 'write', filePath: string, error: Error}\n  }\n}\n```\nThis uses the [interfaces declaration merging](https://www.typescriptlang.org/docs/handbook/declaration-merging.html#merging-interfaces) to make `wari` functions aware of the types of your custom errors.\n\nYou can think of the code above as equivalent to the following (but it doesn't actually create any classes):\n\n```ts\nclass HttpError extends Error {\n  public type = 'HttpError'\n  constructor(public details: {method: 'GET' | 'POST', url: string, status: number}) {\n    super(`HttpError: ${JSON.stringify(details)}`)\n  }\n}\n\nclass JsonError extends Error {\n  public type = 'JsonError'\n  constructor(public details: {text: string}) {\n    super(`JsonError: ${JSON.stringify(details)}`)\n  }\n}\n\nclass FileError extends Error {\n  public type = 'FileError'\n  constructor(public details: {operation: 'read' | 'write', filePath: string, error: Error}) {\n    super(`FileError: ${JSON.stringify(details)}`)\n  }\n}\n```\n\n## Creating Errors\n\nUse the `new` function to create new errors. Typescript will offer you autocomplete for the first argument of the `new` function, so you don't have to remember all errors names. Once you choose a name, the second argument will be typed with the corresponding details type.\n\n**Return errors instead of throwing them.**\n\n```ts\nimport * as E from 'wari'\n\nasync function fetchData() {\n  const res = await fetch('...')\n  if (!res.ok) return E.new('HttpError', {method: 'GET', url: '...', status: res.status})\n  const text = await res.text()\n  try {\n    return JSON.parse(text) as Data\n  } catch (err) {\n    return E.new('JsonError', {text})\n  }\n}\n```\n\n**Note:** The `new` function has an alias called `make`, if you don't want to import all functions by using\n```ts\nimport * as E from 'wari'\n\n// Use `E.new`\n```\nYou can import `make` instead:\n```ts\nimport {make} from 'wari'\n\n// Use `make` instead\n```\n\n## Handling Errors\n\nUse `any`, `is` and `match` functions to handle errors.\n\nUse `any` to check if a value is any error.\n\n```ts\nimport * as E from 'wari'\n\nasync function main() {\n  const data = await fetchData()\n      // ^? Wari\u003c'HttpError'\u003e | Wari\u003c'JsonError'\u003e | Data\n  if (E.any(data)) {\n    // handle the error\n    data\n    // ^? Wari\u003c'HttpError'\u003e | Wari\u003c'JsonError'\u003e\n  } else {\n    // Use the data\n    data\n    // ^? Data\n  }\n}\n```\n\nThe `is` function checks if a value corresponds to a specific error type. Typescript infers the possible types based on the first argument, and acceptes only those types in the second argument.\n\n```ts\nimport * as E from 'wari'\n\nasync function main() {\n  const data = await fetchData()\n      // ^? Wari\u003c'HttpError'\u003e | Wari\u003c'JsonError'\u003e | Data\n  if (E.is(data, 'HttpError')) {\n    data.details\n        // ^? {method: 'GET' | 'POST', url: string, status: number}\n    return;\n  }\n  \n  if (E.is(data, 'JsonError')) {\n    data.details\n        // ^? {text: string}\n    return;\n  }\n\n  data\n  // ^? Data\n}\n```\n\nUse the `match` function to match a value against all possible error types. Typescript infers possible error types and gives you autocomplete. You can handle all or some errors separately and provide a default handler for the remaining errors as the third argument.\n\nif the value given to `match` is not an error, it's simply returned as is. Otherwise, the corresponding handler is called and is returned value is returned.\n\n```ts\nimport * as E from 'wari'\n\nasync function main() {\n  const data = E.match(await fetchData(), {\n    HttpError: err =\u003e {\n            // ^? Err\u003c'HttpError'\u003e\n      return defaultData as Data\n    },\n    JsonError: err =\u003e {\n            // ^? Err\u003c'JsonError'\u003e\n      console.error(err)\n    }\n  })\n  data\n  // ^? Data | undefined\n}\n```\n\n## Catching External Errors\n\nEven if you don't use `throw` in your code, external code may still throw errors when you call it. In that case, you can use `catch` to catch any thrown error and handle it:\n\n```ts\nimport * as E from 'wari'\n\nfunction mayThrow(x: number) {\n  if (x === 42) throw new Error(`Ooops`)\n  return x\n}\n\nE.catch(\n  () =\u003e mayThrow(1),\n  err =\u003e 0\n) //=\u003e 1\n\nE.catch(\n  () =\u003e mayThrow(42),\n  err =\u003e 0\n) //=\u003e 0\n\nE.catch(\n  () =\u003e mayThrow(42),\n  err =\u003e E.new('SomeError')\n) //=\u003e Err\u003c'SomeError'\u003e\n```\n\n**Note:** The `catch` function has an alias called `tryCatch`, if you don't want to import all functions by using\n\n```ts\nimport * as E from 'wari'\n\n// Use `E.catch`\n```\n\nYou can import `tryCatch` instead:\n\n```ts\nimport {tryCatch} from 'wari'\n\n// Use `tryCatch` instead\n```\n\n## Creating Safe Functions\n\nif you are calling a function that may throw multiple times across your code, you can use `safe` to create a safe function (a function that returns instead of throwing) from it. The returned function will take the same arguments and execute the original function:\n\n- if no error is thrown, the result is simply returned.\n- if an error is thrown (or a rejecting promise is returned), the given handler is called with the arguments and the error; its return is returned.\n\n```ts\nimport * as E from 'wari'\n\nconst safeJsonParse = E.safe(JSON.parse, ([text], err) =\u003e E.new('JsonError', {text}))\n\nsafeJsonParse('{\"') //=\u003e Err\u003c'JsonError'\u003e with details {text: '{\"'}\n```\n\n# Contributing\n\nYou can contribute to this library in many ways, including:\n\n- **Reporting bugs**: Simply open an issue and describe the bug. Please include a code snippet to reproduce the bug, it really helps to solve the problem quickly.\n\n- **Suggesting new features**: If you have a feature idea or a use case that is not covered, open an issue and we will discuss it. Do you already have an implementation for it? great, make a pull request and I will review it.\n\nThose are just examples, any issue or pull request is welcome :)\n\n# Changelog\n\n**1.4.3 (November 30th 2024)**\n\n- Fix stringifying circular objects\n\n**1.4.2 (November 29th 2024)**\n\n- Update dependencies and documentation\n- Fix some types\n\n**1.4.1 (November 21st 2023)**\n\n- Update dependencies.\n\n**1.4.0 (September 24th 2023)**\n\n- Change the `catch` function to take a function with no arguments and a handler.\n- Add `safe` function to create safe functions.\n\n**1.3.0 (September 1st 2023)**\n\n-  Change the `match` function to take the default handler as a third argment (instead of `_`) for better typing.\n\n**1.2.0 (August 27 2023)**\n\n- Improve `match` type inference, now the default handler `_` parameter type is only the remaining error types.\n\n**1.1.0 (August 27 2023)**\n\n- Refactor types.\n- Add `new` alias for `make`.\n- Add `any` to check for any wari error.\n- Add `catch` (and `tryCatch` alias) to catch errors and wrap them into `Err\u003c'Unknown'\u003e`.\n\n**1.0.0 (August 14 2023)**\n\n- First version.\n\n**1.0.0-alpha.1 (August 13 2023)**\n\n- First alpha version.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwebneat%2Fwari","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwebneat%2Fwari","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwebneat%2Fwari/lists"}