[
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: [gvergnaud] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]\n# patreon: # Replace with a single Patreon username\n# open_collective: # Replace with a single Open Collective username\n# ko_fi: # Replace with a single Ko-fi username\n# tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel\n# community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry\n# liberapay: # Replace with a single Liberapay username\n# issuehunt: # Replace with a single IssueHunt username\n# otechie: # Replace with a single Otechie username\n# lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry\n# custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**TypeScript playground with a minimal reproduction case**\n\nExample: [Playground](https://www.typescriptlang.org/play/?#code/JYWwDg9gTgLgBAbziAhjAxgCwDRwApwC+cAZlBCHAOQwDOAtGGjAKZQB2VAUFwPS9wA6lGCs4ATwgBXKHCgsw5OOhS0WAOi5A)\n\n**Versions**\n- TypeScript version: x.x.x\n- ts-pattern version: x.x.x\n- environment: browser + version / node version / deno version\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: enhancement\nassignees: ''\n\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".gitignore",
    "content": ".DS_Store\nnode_modules\nnpm-debug.log\nlib\ndist\nnotes.md\n.vscode/\ntracing_output_folder/\ntrace/\n*.tgz"
  },
  {
    "path": ".prettierrc",
    "content": "{\n    \"singleQuote\": true\n}"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2021 Gabriel Vergnaud\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<h1 align=\"center\">TS-Pattern</h1>\n\n<p align=\"center\">\nThe exhaustive Pattern Matching library for <a href=\"https://github.com/microsoft/TypeScript\">TypeScript</a>\nwith smart type inference.\n</p>\n\n<p align=\"center\">\n  <a href=\"https://www.npmjs.com/package/ts-pattern\">\n    <img src=\"https://img.shields.io/npm/dm/ts-pattern.svg\" alt=\"downloads\" height=\"18\">\n  </a>\n  <a href=\"https://www.npmjs.com/package/ts-pattern\">\n    <img src=\"https://img.shields.io/npm/v/ts-pattern.svg\" alt=\"npm version\" height=\"18\">\n  </a>\n  <a href=\"https://github.com/gvergnaud/ts-pattern\">\n    <img src=\"https://img.shields.io/npm/l/ts-pattern.svg\" alt=\"MIT license\" height=\"18\">\n  </a>\n</p>\n\n```tsx\nimport { match, P } from 'ts-pattern';\n\ntype Data =\n  | { type: 'text'; content: string }\n  | { type: 'img'; src: string };\n\ntype Result =\n  | { type: 'ok'; data: Data }\n  | { type: 'error'; error: Error };\n\nconst result: Result = ...;\n\nconst html = match(result)\n  .with({ type: 'error' }, () => <p>Oups! An error occured</p>)\n  .with({ type: 'ok', data: { type: 'text' } }, (res) => <p>{res.data.content}</p>)\n  .with({ type: 'ok', data: { type: 'img', src: P.select() } }, (src) => <img src={src} />)\n  .exhaustive();\n```\n\n## About\n\nWrite **better** and **safer conditions**. Pattern matching lets you express complex conditions in a single, compact expression. Your code becomes **shorter** and **more readable**. Exhaustiveness checking ensures you haven’t forgotten **any possible case**.\n\n![ts-pattern](https://user-images.githubusercontent.com/9265418/231688650-7cd957a9-8edc-4db8-a5fe-61e1c2179d91.gif)\n\n<p align=\"center\"><i>Animation by <a target=\"_blank\" href=\"https://twitter.com/nicoespeon/status/1644342570389061634?s=20\">@nicoespeon</a></i></p>\n\n## Features\n\n- Pattern-match on **any data structure**: nested [Objects](#objects), [Arrays](#tuples-arrays), [Tuples](#tuples-arrays), [Sets](#pset-patterns), [Maps](#pmap-patterns) and all primitive types.\n- **Typesafe**, with helpful [type inference](#type-inference).\n- **Exhaustiveness checking** support, enforcing that you are matching every possible case with [`.exhaustive()`](#exhaustive).\n- Use [patterns](#patterns) to **validate** the shape of your data with [`isMatching`](#ismatching).\n- **Expressive API**, with catch-all and type specific **wildcards**: [`P._`](#p_-wildcard), [`P.string`](#pstring-wildcard), [`P.number`](#pnumber-wildcard), etc.\n- Supports [**predicates**](#pwhen-patterns), [**unions**](#punion-patterns), [**intersections**](#pintersection-patterns) and [**exclusion**](#pnot-patterns) patterns for non-trivial cases.\n- Supports properties selection, via the [`P.select(name?)`](#pselect-patterns) function.\n- Tiny bundle footprint ([**only ~2kB**](https://bundlephobia.com/package/ts-pattern)).\n\n## What is Pattern Matching?\n\n[Pattern Matching](https://en.wikipedia.org/wiki/Pattern_matching) is a code-branching technique coming from functional programming languages that's more powerful and often less verbose than imperative alternatives (if/else/switch statements), especially for complex conditions.\n\nPattern Matching is implemented in Python, Rust, Swift, Elixir, Haskell and many other languages. There is [a tc39 proposal](https://github.com/tc39/proposal-pattern-matching) to add Pattern Matching to EcmaScript, but it is still in stage 1 and isn't likely to land before several years. Luckily, pattern matching can be implemented in userland. `ts-pattern` Provides a typesafe pattern matching implementation that you can start using today.\n\nRead the introduction blog post: [Bringing Pattern Matching to TypeScript 🎨 Introducing TS-Pattern](https://dev.to/gvergnaud/bringing-pattern-matching-to-typescript-introducing-ts-pattern-v3-0-o1k)\n\n## Installation\n\nVia npm\n\n```sh\nnpm install ts-pattern\n```\n\nYou can also use your favorite package manager:\n\n```sh\npnpm add ts-pattern\n# OR\nyarn add ts-pattern\n# OR\nbun add ts-pattern\n# OR\nnpx jsr add @gabriel/ts-pattern\n```\n\n## Want to become a TypeScript Expert?\n\nCheck out 👉 [Type-Level TypeScript](https://type-level-typescript.com/), an online course teaching you how to unleash the full potential of TypeScript's Turing-complete type system. You already know how to code, and types are simply another programming language to master. This course **bridges the gap**, helping you apply your **existing programming knowledge** to **TypeScript's type system**, so you never again struggle with type errors or feel unable to type complex generic code correctly!\n\n# Documentation\n\n- [Sandbox examples](#sandbox-examples)\n- [Getting Started](#getting-started)\n- [API Reference](#api-reference)\n  - [`match`](#match)\n  - [`.with`](#with)\n  - [`.when`](#when)\n  - [`.returnType`](#returntype)\n  - [`.exhaustive`](#exhaustive)\n  - [`.otherwise`](#otherwise)\n  - [`.narrow`](#narrow)\n  - [`isMatching`](#ismatching)\n  - [Patterns](#patterns)\n    - [Literals](#literals)\n    - [Wildcards](#wildcards)\n    - [Objects](#objects)\n    - [Tuples (arrays)](#tuples-arrays)\n    - [`P.array` patterns](#parray-patterns)\n    - [`P.record` patterns](#precord-patterns)\n    - [`P.set`](#pset-patterns)\n    - [`P.map`](#pmap-patterns)\n    - [`P.when` patterns](#pwhen-patterns)\n    - [`P.not` patterns](#pnot-patterns)\n    - [`P.select` patterns](#pselect-patterns)\n    - [`P.optional` patterns](#poptional-patterns)\n    - [`P.instanceOf` patterns](#pinstanceof-patterns)\n    - [`P.union` patterns](#punion-patterns)\n    - [`P.intersection` patterns](#pintersection-patterns)\n    - [`P.string` predicates](#pstring-predicates)\n    - [`P.number` and `P.bigint` predicates](#pnumber-and-pbigint-predicates)\n  - [Types](#types)\n    - [`P.infer`](#pinfer)\n    - [`P.Pattern`](#pPattern)\n    - [Type inference](#type-inference)\n- [Inspirations](#inspirations)\n\n## Sandbox examples\n\n- [Basic Demo](https://stackblitz.com/edit/vitejs-vite-qrk8po?file=src%2Fexamples%2Fbasic.tsx)\n- [React gif fetcher app Demo](https://stackblitz.com/edit/ts-pattern-gifs?file=src%2FApp.tsx)\n- [React.useReducer Demo](https://stackblitz.com/edit/ts-pattern-reducer?file=src%2FApp.tsx)\n- [Handling untyped API response Demo](https://stackblitz.com/edit/vitejs-vite-qrk8po?file=src%2Fexamples%2Fapi.tsx)\n- [`P.when` Guard Demo](https://stackblitz.com/edit/vitejs-vite-qrk8po?file=src%2Fexamples%2Fwhen.tsx)\n- [`P.not` Pattern Demo](https://stackblitz.com/edit/vitejs-vite-qrk8po?file=src%2Fexamples%2Fnot.tsx)\n- [`P.select` Pattern Demo](https://stackblitz.com/edit/vitejs-vite-qrk8po?file=src%2Fexamples%2Fselect.tsx)\n- [`P.union` Pattern Demo](https://stackblitz.com/edit/vitejs-vite-qrk8po?file=src%2Fexamples%2Funion.tsx)\n\n## Getting Started\n\nAs an example, let's create a state reducer for a frontend application that fetches some data.\n\n### Example: a state reducer with ts-pattern\n\nOur application can be in four different states: `idle`, `loading`,\n`success` and `error`. Depending on which state we are in, some events\ncan occur. Here are all the possible types of event our application\ncan respond to: `fetch`, `success`, `error` and `cancel`.\n\nI use the word `event` but you can replace it with `action` if you are used\nto Redux's terminology.\n\n```ts\ntype State =\n  | { status: 'idle' }\n  | { status: 'loading'; startTime: number }\n  | { status: 'success'; data: string }\n  | { status: 'error'; error: Error };\n\ntype Event =\n  | { type: 'fetch' }\n  | { type: 'success'; data: string }\n  | { type: 'error'; error: Error }\n  | { type: 'cancel' };\n```\n\nEven though our application can handle 4 events, **only a subset** of these\nevents **make sense for each given state**. For instance we can only `cancel`\na request if we are currently in the `loading` state.\nTo avoid unwanted state changes that could lead to bugs, we want our state reducer function to branch on **both the state and the event**, and return a new state.\n\nThis is a case where `match` really shines. Instead of writing nested switch statements, we can use pattern matching to simultaneously check the state and the event object:\n\n<!-- prettier-ignore -->\n```ts\nimport { match, P } from 'ts-pattern';\n\nconst reducer = (state: State, event: Event) =>\n  match([state, event])\n    .returnType<State>()\n    .with(\n      [{ status: 'loading' }, { type: 'success' }],\n      ([_, event]) => ({ status: 'success', data: event.data })\n    )\n    .with(\n      [{ status: 'loading' }, { type: 'error', error: P.select() }],\n      (error) => ({ status: 'error', error })\n    )\n    .with(\n      [{ status: P.not('loading') }, { type: 'fetch' }],\n      () => ({ status: 'loading', startTime: Date.now() })\n    )\n    .with(\n      [\n        {\n          status: 'loading',\n          startTime: P.when((t) => t + 2000 < Date.now()),\n        },\n        { type: 'cancel' },\n      ],\n      () => ({ status: 'idle' })\n    )\n    .with(P._, () => state)\n    .exhaustive();\n```\n\nThere's a lot going on, so **let's go through this code bit by bit:**\n\n### match(value)\n\n`match` takes a value and returns a [_builder_](https://en.wikipedia.org/wiki/Builder_pattern) on which you can add your pattern matching cases.\n\n<!-- prettier-ignore -->\n```ts\nmatch([state, event])\n```\n\nIt's also possible to specify the input and output type explicitly with `match<Input, Output>(...)`, but this is usually unnecessary, as TS-Pattern is able to infer them.\n\n### .returnType\\<OutputType\\>()\n\n`.returnType` is an optional method that you can call if you want to force all following code-branches to return a value of a specific type. It takes a single type parameter, provided between `<AngleBrackets>`.\n\n```ts\n  .returnType<State>()\n```\n\nHere, we use this method to make sure all branches return a valid `State` object.\n\n### .with(pattern, handler)\n\nThen we add a first `with` clause:\n\n```ts\n  .with(\n    [{ status: 'loading' }, { type: 'success' }],\n    ([state, event]) => ({\n      // `state` is inferred as { status: 'loading' }\n      // `event` is inferred as { type: 'success', data: string }\n      status: 'success',\n      data: event.data,\n    })\n  )\n```\n\nThe first argument is the **pattern**: the **shape of value** you expect for this branch.\n\nThe second argument is the **handler function**: the code **branch** that will be called if the input value matches the pattern.\n\nThe handler function takes the input value as first parameter with its type **narrowed down** to what the pattern matches.\n\n### P.select(name?)\n\nIn the second `with` clause, we use the `P.select` function:\n\n```ts\n  .with(\n    [\n      { status: 'loading' },\n      { type: 'error', error: P.select() }\n    ],\n    (error) => ({ status: 'error', error })\n  )\n```\n\n`P.select()` lets you **extract** a piece of your input value and **inject** it into your handler. It is pretty useful when pattern matching on deep data structures because it avoids the hassle of destructuring your input in your handler.\n\nSince we didn't pass any name to `P.select()`, It will inject the `event.error` property as first argument to the handler function. Note that you can still access **the full input value** with its type narrowed by your pattern as **second argument** of the handler function:\n\n```ts\n  .with(\n    [\n      { status: 'loading' },\n      { type: 'error', error: P.select() }\n    ],\n    (error, stateAndEvent) => {\n      // error: Error\n      // stateAndEvent: [{ status: 'loading' }, { type: 'error', error: Error }]\n    }\n  )\n```\n\nIn a pattern, we can only have a **single** anonymous selection. If you need to select more properties on your input data structure, you will need to give them **names**:\n\n```ts\n.with(\n    [\n      { status: 'success', data: P.select('prevData') },\n      { type: 'error', error: P.select('err') }\n    ],\n    ({ prevData, err }) => {\n      // Do something with (prevData: string) and (err: Error).\n    }\n  )\n```\n\nEach named selection will be injected inside a `selections` object, passed as first argument to the handler function. Names can be any strings.\n\n### P.not(pattern)\n\nIf you need to match on everything **but** a specific value, you can use a `P.not(<pattern>)` pattern. it's a function taking a pattern and returning its opposite:\n\n```ts\n  .with(\n    [{ status: P.not('loading') }, { type: 'fetch' }],\n    () => ({ status: 'loading' })\n  )\n```\n\n### `P.when()` and guard functions\n\nSometimes, we need to make sure our input value respects a condition that can't be expressed by a pattern. For example, imagine you need to check that a number is positive. In these cases, we can use **guard functions**: functions taking a value and returning a `boolean`.\n\nWith TS-Pattern, there are two ways to use a guard function:\n\n- use `P.when(<guard function>)` inside one of your patterns\n- pass it as second parameter to `.with(...)`\n\n#### using P.when(predicate)\n\n```ts\n  .with(\n    [\n      {\n        status: 'loading',\n        startTime: P.when((t) => t + 2000 < Date.now()),\n      },\n      { type: 'cancel' },\n    ],\n    () => ({ status: 'idle' })\n  )\n```\n\n#### Passing a guard function to `.with(...)`\n\n`.with` optionally accepts a guard function as second parameter, between\nthe `pattern` and the `handler` callback:\n\n```ts\n  .with(\n    [{ status: 'loading' }, { type: 'cancel' }],\n    ([state, event]) => state.startTime + 2000 < Date.now(),\n    () => ({ status: 'idle' })\n  )\n```\n\nThis pattern will only match if the guard function returns `true`.\n\n### the `P._` wildcard\n\n`P._` will match any value. You can use it either at the top level, or within another pattern.\n\n```ts\n  .with(P._, () => state)\n\n  // You could also use it inside another pattern:\n  .with([P._, P._], () => state)\n\n  // at any level:\n  .with([P._, { type: P._ }], () => state)\n\n```\n\n### .exhaustive(), .otherwise() and .run()\n\n```ts\n  .exhaustive();\n```\n\n`.exhaustive()` **executes** the pattern matching expression, and **returns the result**. It also enables **exhaustiveness checking**, making sure we don't forget any possible case in our input value. This extra type safety is very nice because forgetting a case is an easy mistake to make, especially in an evolving code-base.\n\nNote that exhaustive pattern matching is **optional**. It comes with the trade-off of having slightly **longer compilation times** because the type checker has more work to do.\n\nAlternatively, you can use `.otherwise()`, which takes an handler function returning a default value. `.otherwise(handler)` is equivalent to `.with(P._, handler).exhaustive()`.\n\n```ts\n  .otherwise(() => state);\n```\n\n### Matching several patterns\n\nAs you may know, `switch` statements allow handling several cases with\nthe same code block:\n\n```ts\nswitch (type) {\n  case 'text':\n  case 'span':\n  case 'p':\n    return 'text';\n\n  case 'btn':\n  case 'button':\n    return 'button';\n}\n```\n\nSimilarly, ts-pattern lets you pass several patterns to `.with()` and if\none of these patterns matches your input, the handler function will be called:\n\n```ts\nconst sanitize = (name: string) =>\n  match(name)\n    .with('text', 'span', 'p', () => 'text')\n    .with('btn', 'button', () => 'button')\n    .otherwise(() => name);\n\nsanitize('span'); // 'text'\nsanitize('p'); // 'text'\nsanitize('button'); // 'button'\n```\n\nAs you might expect, this also works with more complex patterns than strings and exhaustiveness checking works as well.\n\n## API Reference\n\n### `match`\n\n```ts\nmatch(value);\n```\n\nCreate a `Match` object on which you can later call `.with`, `.when`, `.otherwise` and `.run`.\n\n#### Signature\n\n```ts\nfunction match<TInput, TOutput>(input: TInput): Match<TInput, TOutput>;\n```\n\n#### Arguments\n\n- `input`\n  - **Required**\n  - the input value your patterns will be tested against.\n\n### `.with`\n\n```ts\nmatch(...)\n  .with(pattern, [...patterns], handler)\n```\n\n#### Signature\n\n```ts\nfunction with(\n  pattern: Pattern<TInput>,\n  handler: (selections: Selections<TInput>, value: TInput) => TOutput\n): Match<TInput, TOutput>;\n\n// Overload for multiple patterns\nfunction with(\n  pattern1: Pattern<TInput>,\n  ...patterns: Pattern<TInput>[],\n  // no selection object is provided when using multiple patterns\n  handler: (value: TInput) => TOutput\n): Match<TInput, TOutput>;\n\n// Overload for guard functions\nfunction with(\n  pattern: Pattern<TInput>,\n  when: (value: TInput) => unknown,\n  handler: (\n    selection: Selection<TInput>,\n    value: TInput\n  ) => TOutput\n): Match<TInput, TOutput>;\n```\n\n#### Arguments\n\n- `pattern: Pattern<TInput>`\n  - **Required**\n  - The pattern your input must match for the handler to be called.\n  - [See all valid patterns below](#patterns)\n  - If you provide several patterns before providing the `handler`, the `with` clause will match if one of the patterns matches.\n- `when: (value: TInput) => unknown`\n  - Optional\n  - Additional condition the input must satisfy for the handler to be called.\n  - The input will match if your guard function returns a truthy value.\n  - `TInput` might be narrowed to a more precise type using the `pattern`.\n- `handler: (selections: Selections<TInput>, value: TInput) => TOutput`\n  - **Required**\n  - Function called when the match conditions are satisfied.\n  - All handlers on a single `match` case must return values of the same type, `TOutput`.\n  - `selections` is an object of properties selected from the input with the [`select` function](#select-patterns).\n  - `TInput` might be narrowed to a more precise type using the `pattern`.\n\n### `.when`\n\n```ts\nmatch(...)\n  .when(predicate, handler)\n```\n\n#### Signature\n\n```ts\nfunction when(\n  predicate: (value: TInput) => unknown,\n  handler: (value: TInput) => TOutput\n): Match<TInput, TOutput>;\n```\n\n#### Arguments\n\n- `predicate: (value: TInput) => unknown`\n  - **Required**\n  - Condition the input must satisfy for the handler to be called.\n- `handler: (value: TInput) => TOutput`\n  - **Required**\n  - Function called when the predicate condition is satisfied.\n  - All handlers on a single `match` case must return values of the same type, `TOutput`.\n\n### `.returnType`\n\n```ts\nmatch(...)\n  .returnType<string>()\n  .with(..., () => \"has to be a string\")\n  .with(..., () => \"Oops\".length)\n  //               ~~~~~~~~~~~~~ ❌ `number` isn't a string!\n```\n\nThe `.returnType<SomeType>()` method allows you to control the return type of all of your branches of code. It accepts a single type parameter that will be used as the return type of your `match` expression. All code branches must return values assignable to this type.\n\n#### Signature\n\n```ts\nfunction returnType<TOutputOverride>(): Match<TInput, TOutputOverride>;\n```\n\n#### Type arguments\n\n- `TOutputOverride`\n  - The type that your `match` expression will return. All branches must return values assignable to it.\n\n### `.exhaustive`\n\n```ts\nmatch(...)\n  .with(...)\n  .exhaustive()\n```\n\nRuns the pattern-matching expression and returns its result. It also enables exhaustiveness checking, making sure that we have handled all possible cases **at compile time**.\n\nBy default, `.exhaustive()` will throw an error if the input value wasn't handled by any `.with(...)` clause. This should only happen if your types are incorrect.\n\nIt is possible to pass your own handler function as a parameter to decide what should happen if an unexpected value has been received. You can for example throw your own custom error:\n\n```ts\nmatch(...)\n  .with(...)\n  .exhaustive((unexpected: unknown) => {\n    throw MyCustomError(unexpected);\n  })\n```\n\nOr log an error and return a default value:\n\n```ts\nmatch<string, number>(...)\n  .with(P.string, (str) => str.length)\n  .exhaustive((notAString: unknown) => {\n    console.log(`received an unexpected value: ${notAString}`);\n    return 0;\n  })\n```\n\n#### Signature\n\n```ts\nfunction exhaustive(): TOutput;\nfunction exhaustive(handler: (unexpectedValue: unknown) => TOutput): TOutput;\n```\n\n#### Example\n\n```ts\ntype Permission = 'editor' | 'viewer';\ntype Plan = 'basic' | 'pro';\n\nconst fn = (org: Plan, user: Permission) =>\n  match([org, user])\n    .with(['basic', 'viewer'], () => {})\n    .with(['basic', 'editor'], () => {})\n    .with(['pro', 'viewer'], () => {})\n    // Fails with `NonExhaustiveError<['pro', 'editor']>`\n    // because the `['pro', 'editor']` case isn't handled.\n    .exhaustive();\n\nconst fn2 = (org: Plan, user: Permission) =>\n  match([org, user])\n    .with(['basic', 'viewer'], () => {})\n    .with(['basic', 'editor'], () => {})\n    .with(['pro', 'viewer'], () => {})\n    .with(['pro', 'editor'], () => {})\n    .exhaustive(); // Works!\n```\n\n### `.otherwise`\n\n```ts\nmatch(...)\n  .with(...)\n  .otherwise(defaultHandler)\n```\n\nRuns the pattern-matching expression with a default handler which will be called if no previous `.with()` clause match the input value, and returns the result.\n\n#### Signature\n\n```ts\nfunction otherwise(defaultHandler: (value: TInput) => TOutput): TOutput;\n```\n\n#### Arguments\n\n- `defaultHandler: (value: TInput) => TOutput`\n  - **Required**\n  - Function called if no pattern matched the input value.\n  - Think of it as the `default:` case of `switch` statements.\n  - All handlers on a single `match` case must return values of the same type, `TOutput`.\n\n### `.run`\n\n```ts\nmatch(...)\n  .with(...)\n  .run()\n```\n\nreturns the result of the pattern-matching expression, or **throws** if no pattern matched the input. `.run()` is similar to `.exhaustive()`, but is **unsafe** because exhaustiveness is not checked at compile time, so you have no guarantees that all cases are indeed covered. Use at your own risks.\n\n#### Signature\n\n```ts\nfunction run(): TOutput;\n```\n\n### `.narrow`\n\n```ts\nmatch(...)\n  .with(...)\n  .narrow()\n  .with(...)\n```\n\nThe `.narrow()` method deeply narrows the input type to exclude all values that have previously been handled. This is useful when you want to exclude cases from union types or nullable properties that are deeply nested.\n\nNote that handled case of top-level union types are excluded by default, without calling `.narrow()`.\n\n#### Signature\n\n```ts\nfunction narrow(): Match<Narrowed<TInput>, TOutput>;\n```\n\n#### Example\n\n```ts\ntype Input = { color: 'red' | 'blue'; size: 'small' | 'large' };\n\ndeclare const input: Input;\n\nconst result = match(input)\n  .with({ color: 'red', size: 'small' }, (red) => `Red: ${red.size}`)\n  .with({ color: 'blue', size: 'large' }, (red) => `Red: ${red.size}`)\n  .narrow() // 👈\n  .otherwise((narrowedInput) => {\n    // narrowedInput:\n    // | { color: 'red'; size: 'large' }\n    // | { color: 'blue'; size: 'small' }\n  });\n```\n\n### `isMatching`\n\n```ts\nif (isMatching(pattern, value))  {\n  ...\n}\n```\n\n`isMatching` is a type guard function which checks if a pattern matches a given value. It is _curried_, which means it can be used in two ways.\n\nWith a single argument:\n\n```ts\nimport { isMatching, P } from 'ts-pattern';\n\nconst isBlogPost = isMatching({\n  type: 'blogpost',\n  title: P.string,\n  description: P.string,\n});\n\nif (isBlogPost(value)) {\n  // value: { type: 'blogpost', title: string, description: string }\n}\n```\n\nWith two arguments:\n\n```ts\nconst blogPostPattern = {\n  type: 'blogpost',\n  title: P.string,\n  description: P.string,\n} as const;\n\nif (isMatching(blogPostPattern, value)) {\n  // value: { type: 'blogpost', title: string, description: string }\n}\n```\n\n#### Signature\n\n```ts\nexport function isMatching<p extends Pattern<any>>(\n  pattern: p\n): (value: any) => value is InvertPattern<p>;\nexport function isMatching<p extends Pattern<any>>(\n  pattern: p,\n  value: any\n): value is InvertPattern<p>;\n```\n\n#### Arguments\n\n- `pattern: Pattern<any>`\n  - **Required**\n  - The pattern a value should match.\n- `value?: any`\n  - **Optional**\n  - if a value is given as second argument, `isMatching` will return a boolean telling us whether the pattern matches the value or not.\n  - if we only give the pattern to the function, `isMatching` will return another **type guard function** taking a value and returning a boolean which tells us whether the pattern matches the value or not.\n\n## Patterns\n\nA pattern is a description of the expected shape of your input value.\n\nPatterns can be regular JavaScript values (`\"some string\"`, `10`, `true`, ...), data structures ([objects](#objects), [arrays](#tuples-arrays), ...), wildcards ([`P._`](#p_-wildcard), [`P.string`](#pstring-wildcard), [`P.number`](#pnumber-wildcard), ...), or special matcher functions ([`P.not`](#pnot-patterns),\n[`P.when`](#pwhen-patterns), [`P.select`](#pselect-patterns), ...).\n\nAll wildcards and matcher functions can be imported either as `Pattern` or as `P` from the `ts-pattern` module.\n\n```ts\nimport { match, Pattern } from 'ts-pattern';\n\nconst toString = (value: unknown): string =>\n  match(value)\n    .with(Pattern.string, (str) => str)\n    .with(Pattern.number, (num) => num.toFixed(2))\n    .with(Pattern.boolean, (bool) => `${bool}`)\n    .otherwise(() => 'Unknown');\n```\n\nOr\n\n```ts\nimport { match, P } from 'ts-pattern';\n\nconst toString = (value: unknown): string =>\n  match(value)\n    .with(P.string, (str) => str)\n    .with(P.number, (num) => num.toFixed(2))\n    .with(P.boolean, (bool) => `${bool}`)\n    .otherwise(() => 'Unknown');\n```\n\nIf your input isn't typed, (if it's a `any` or a `unknown`), you are free to use any possible pattern. Your handler will infer the input type from the shape of your pattern.\n\n### Literals\n\nLiterals are primitive JavaScript values, like `numbers`, `strings`, `booleans`, `bigints`, `symbols`, `null`, `undefined`, or `NaN`.\n\n```ts\nimport { match } from 'ts-pattern';\n\nconst input: unknown = 2;\n\nconst output = match(input)\n  .with(2, () => 'number: two')\n  .with(true, () => 'boolean: true')\n  .with('hello', () => 'string: hello')\n  .with(undefined, () => 'undefined')\n  .with(null, () => 'null')\n  .with(NaN, () => 'number: NaN')\n  .with(20n, () => 'bigint: 20n')\n  .otherwise(() => 'something else');\n\nconsole.log(output);\n// => 'number: two'\n```\n\n### Objects\n\nPatterns can be objects containing sub-patterns. An object pattern will match\nIf and only if the input value **is an object**, contains **all properties** the pattern defines\nand each property **matches** the corresponding sub-pattern.\n\n```ts\nimport { match } from 'ts-pattern';\n\ntype Input =\n  | { type: 'user'; name: string }\n  | { type: 'image'; src: string }\n  | { type: 'video'; seconds: number };\n\nlet input: Input = { type: 'user', name: 'Gabriel' };\n\nconst output = match(input)\n  .with({ type: 'image' }, () => 'image')\n  .with({ type: 'video', seconds: 10 }, () => 'video of 10 seconds.')\n  .with({ type: 'user' }, ({ name }) => `user of name: ${name}`)\n  .otherwise(() => 'something else');\n\nconsole.log(output);\n// => 'user of name: Gabriel'\n```\n\n### Tuples (arrays)\n\nIn TypeScript, [Tuples](https://en.wikipedia.org/wiki/Tuple) are arrays with a fixed\nnumber of elements that can be of different types. You can pattern-match on tuples\nusing a tuple pattern. A tuple pattern will match if the input value **is an array of the same length**,\nand each item matches the corresponding sub-pattern.\n\n```ts\nimport { match, P } from 'ts-pattern';\n\ntype Input =\n  | [number, '+', number]\n  | [number, '-', number]\n  | [number, '*', number]\n  | ['-', number];\n\nconst input = [3, '*', 4] as Input;\n\nconst output = match(input)\n  .with([P._, '+', P._], ([x, , y]) => x + y)\n  .with([P._, '-', P._], ([x, , y]) => x - y)\n  .with([P._, '*', P._], ([x, , y]) => x * y)\n  .with(['-', P._], ([, x]) => -x)\n  .exhaustive();\n\nconsole.log(output);\n// => 12\n```\n\n### Wildcards\n\n#### `P._` wildcard\n\nThe `P._` pattern will match any value. You can also use `P.any`, which is an alias to `P._`.\n\n```ts\nimport { match, P } from 'ts-pattern';\n\nconst input = 'hello';\n\nconst output = match(input)\n  .with(P._, () => 'It will always match')\n  // OR\n  .with(P.any, () => 'It will always match')\n  .otherwise(() => 'This string will never be used');\n\nconsole.log(output);\n// => 'It will always match'\n```\n\n#### `P.string` wildcard\n\nThe `P.string` pattern will match any value of type `string`.\n\n```ts\nimport { match, P } from 'ts-pattern';\n\nconst input = 'hello';\n\nconst output = match(input)\n  .with('bonjour', () => 'Won‘t match')\n  .with(P.string, () => 'it is a string!')\n  .exhaustive();\n\nconsole.log(output);\n// => 'it is a string!'\n```\n\n#### `P.number` wildcard\n\nThe `P.number` pattern will match any value of type `number`.\n\n```ts\nimport { match, P } from 'ts-pattern';\n\nconst input = 2;\n\nconst output = match<number | string>(input)\n  .with(P.string, () => 'it is a string!')\n  .with(P.number, () => 'it is a number!')\n  .exhaustive();\n\nconsole.log(output);\n// => 'it is a number!'\n```\n\n#### `P.boolean` wildcard\n\nThe `P.boolean` pattern will match any value of type `boolean`.\n\n```ts\nimport { match, P } from 'ts-pattern';\n\nconst input = true;\n\nconst output = match<number | string | boolean>(input)\n  .with(P.string, () => 'it is a string!')\n  .with(P.number, () => 'it is a number!')\n  .with(P.boolean, () => 'it is a boolean!')\n  .exhaustive();\n\nconsole.log(output);\n// => 'it is a boolean!'\n```\n\n#### `P.nullish` wildcard\n\nThe `P.nullish` pattern will match any value of type `null` or `undefined`.\n\nEven though `null` and `undefined` can be used as literal patterns, sometimes they appear in a union together\n(e.g. `null | undefined | string`) and you may want to treat them as equivalent using `P.nullish`.\n\n```ts\nimport { match, P } from 'ts-pattern';\n\nconst input = null;\n\nconst output = match<number | null | undefined>(input)\n  .with(P.number, () => 'it is a number!')\n  .with(P.nullish, () => 'it is either null or undefined!')\n  .exhaustive();\n\nconsole.log(output);\n// => 'it is either null or undefined!'\n```\n\n#### `P.nonNullable` wildcard\n\nThe `P.nonNullable` pattern will match any value except `null` or `undefined`.\n\n```ts\nimport { match, P } from 'ts-pattern';\n\nconst input = null;\n\nconst output = match<number | null | undefined>(input)\n  .with(P.nonNullable, () => 'it is a number!')\n  .otherwise(() => 'it is either null or undefined!');\n\nconsole.log(output);\n// => 'it is either null or undefined!'\n```\n\n#### `P.bigint` wildcard\n\nThe `P.bigint` pattern will match any value of type `bigint`.\n\n```ts\nimport { match, P } from 'ts-pattern';\n\nconst input = 20000000n;\n\nconst output = match<bigint | null>(input)\n  .with(P.bigint, () => 'it is a bigint!')\n  .otherwise(() => '?');\n\nconsole.log(output);\n// => 'it is a bigint!'\n```\n\n#### `P.symbol` wildcard\n\nThe `P.symbol` pattern will match any value of type `symbol`.\n\n```ts\nimport { match, P } from 'ts-pattern';\n\nconst input = Symbol('some symbol');\n\nconst output = match<symbol | null>(input)\n  .with(P.symbol, () => 'it is a symbol!')\n  .otherwise(() => '?');\n\nconsole.log(output);\n// => 'it is a symbol!'\n```\n\n### `P.array` patterns\n\nTo match on arrays of unknown size, you can use `P.array(subpattern)`.\nIt takes a sub-pattern, and will match if **all elements** in the input\narray match this sub-pattern.\n\n```ts\nimport { match, P } from 'ts-pattern';\n\ntype Input = { title: string; content: string }[];\n\nlet input: Input = [\n  { title: 'Hello world!', content: 'This is a very interesting content' },\n  { title: 'Bonjour!', content: 'This is a very interesting content too' },\n];\n\nconst output = match(input)\n  .with(\n    P.array({ title: P.string, content: P.string }),\n    (posts) => 'a list of posts!'\n  )\n  .otherwise(() => 'something else');\n\nconsole.log(output);\n// => 'a list of posts!'\n```\n\n### Matching variadic tuples with `P.array`\n\nIn TypeScript, [Variadic Tuple Types](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-0.html#variadic-tuple-types) are array types created with the `...` spread operator, like `[string, ...string[]]`, `[number, ...boolean[], string]` etc. You can match against variadic tuple types using array literals containing `...P.array(subpattern)`:\n\n```ts\nimport { match, P } from 'ts-pattern';\n\ntype Input = (number | string)[];\n\ndeclare const input: Input;\n\nconst output = match(input)\n  // P.array's parameter is optional\n  .with([P.string, ...P.array()], (input) => input) // input: [string, ...(number | string)[]]\n  .with(['print', ...P.array(P.string)], (input) => input) // input: ['print', ...string[]]\n  // you can put patterns on either side of `...P.array()`:\n  .with([...P.array(P.string), 'end'], (input) => input) // input: [...string[], 'end']\n  .with(['start', ...P.array(P.string), 'end'], (input) => input) // input: ['start', ...string[], 'end']\n  .otherwise((input) => input);\n```\n\n### `P.record` patterns\n\nTo match a `Record<Key, Value>` (an object with consistent key and value types), you can use `P.record(keyPattern, valuePattern)`.\nIt takes a sub-pattern to match against the key, a sub-pattern to match against the value, and will match if **all entries** in the object\nmatch these two sub-patterns.\n\n```ts\nimport { match, P } from 'ts-pattern';\n\ntype Input = Record<string, number>;\n\nconst input: Input = {\n  alice: 100,\n  bob: 85,\n  charlie: 92,\n};\n\nconst output = match(input)\n  .with(P.record(P.string, P.number), (scores) => `All user scores`)\n  .with(P.record(P.string, P.string), (names) => `All user names`)\n  .otherwise(() => '');\n\nconsole.log(output);\n// => \"All user scores\"\n```\n\nYou can also use `P.record` with a single argument `P.record(valuePattern)`, which assumes string keys:\n\n```ts\nconst userProfiles = {\n  alice: { name: 'Alice', age: 25 },\n  bob: { name: 'Bob', age: 30 },\n};\n\nconst output = match(userProfiles)\n  .with(\n    P.record({ name: P.string, age: P.number }),\n    (profiles) => `User profiles with name and age`\n  )\n  .otherwise(() => 'Different format');\n\nconsole.log(output);\n// => \"User profiles with name and age\"\n```\n\nWhen using `P.select` in record patterns, you can extract all keys or all values as arrays:\n\n```ts\nconst data = { a: 1, b: 2, c: 3 };\n\nconst keys = match(data)\n  .with(P.record(P.string.select(), P.number), (keys) => keys)\n  .otherwise(() => []);\n\nconst values = match(data)\n  .with(P.record(P.string, P.number.select()), (values) => values)\n  .otherwise(() => []);\n\nconsole.log(keys); // => ['a', 'b', 'c']\nconsole.log(values); // => [1, 2, 3]\n```\n\n### `P.set` patterns\n\nTo match a Set, you can use `P.set(subpattern)`.\nIt takes a sub-pattern, and will match if **all elements** inside the set\nmatch this sub-pattern.\n\n```ts\nimport { match, P } from 'ts-pattern';\n\ntype Input = Set<string | number>;\n\nconst input: Input = new Set([1, 2, 3]);\n\nconst output = match(input)\n  .with(P.set(1), (set) => `Set contains only 1`)\n  .with(P.set(P.string), (set) => `Set contains only strings`)\n  .with(P.set(P.number), (set) => `Set contains only numbers`)\n  .otherwise(() => '');\n\nconsole.log(output);\n// => \"Set contains only numbers\"\n```\n\n### `P.map` patterns\n\nTo match a Map, you can use `P.map(keyPattern, valuePattern)`.\nIt takes a subpattern to match against the key, a subpattern to match agains the value, and will match if **all elements** inside this map\nmatch these two sub-patterns.\n\n```ts\nimport { match, P } from 'ts-pattern';\n\ntype Input = Map<string, string | number>;\n\nconst input: Input = new Map([\n  ['a', 1],\n  ['b', 2],\n  ['c', 3],\n]);\n\nconst output = match(input)\n  .with(P.map(P.string, P.number), (map) => `map's type is Map<string, number>`)\n  .with(P.map(P.string, P.string), (map) => `map's type is Map<string, string>`)\n  .with(\n    P.map(P.union('a', 'c'), P.number),\n    (map) => `map's type is Map<'a' | 'c', number>`\n  )\n  .otherwise(() => '');\n\nconsole.log(output);\n// => \"map's type is Map<string, number>\"\n```\n\n### `P.when` patterns\n\n`P.when` lets you define your own logic to check if the pattern should match or not.\nIf the `predicate` function given to when returns a truthy value, then the pattern\nwill match for this input.\n\nNote that you can narrow down the type of your input by providing a\n[Type Guard function](https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards) to `P.when`.\n\n```ts\nimport { match, P } from 'ts-pattern';\n\ntype Input = { score: number };\n\nconst output = match<Input>({ score: 10 })\n  .with(\n    {\n      score: P.when((score): score is 5 => score === 5),\n    },\n    (input) => '😐' // input is inferred as { score: 5 }\n  )\n  .with({ score: P.when((score) => score < 5) }, () => '😞')\n  .otherwise(() => '🙂');\n\nconsole.log(output);\n// => '🙂'\n```\n\n### `P.not` patterns\n\n`P.not` lets you match on everything **but** a specific value.\nit's a function taking a pattern and returning the opposite pattern.\n\n```ts\nimport { match, P } from 'ts-pattern';\n\ntype Input = boolean | number;\n\nconst toNumber = (input: Input) =>\n  match(input)\n    .with(P.not(P.boolean), (n) => n) // n: number\n    .with(true, () => 1)\n    .with(false, () => 0)\n    .exhaustive();\n\nconsole.log(toNumber(2));\n// => 2\nconsole.log(toNumber(true));\n// => 1\n```\n\n### `P.select` patterns\n\n`P.select` lets you pick a piece of your input data-structure\nand injects it in your handler function.\n\nIt's especially useful when pattern matching on deep data structure to\navoid the hassle of destructuring it in the handler function.\n\nSelections can be either named (with `P.select('someName')`) or anonymous (with `P.select()`).\n\nYou can have only one anonymous selection by pattern, and the selected value will be directly inject in your handler as first argument:\n\n```ts\nimport { match, P } from 'ts-pattern';\n\ntype Input =\n  | { type: 'post'; user: { name: string } }\n  | { ... };\n\nconst input: Input = { type: 'post', user: { name: 'Gabriel' } }\n\nconst output = match(input)\n    .with(\n      { type: 'post', user: { name: P.select() } },\n      username => username // username: string\n    )\n    .otherwise(() => 'anonymous');\n\nconsole.log(output);\n// => 'Gabriel'\n```\n\nIf you need to select several things inside your input data structure, you can name your selections by giving a string to `P.select(<name>)`. Each selection will be passed as first argument to your handler in an object.\n\n```ts\nimport { match, P } from 'ts-pattern';\n\ntype Input =\n  | { type: 'post'; user: { name: string }, content: string }\n  | { ... };\n\nconst input: Input = { type: 'post', user: { name: 'Gabriel' }, content: 'Hello!' }\n\nconst output = match(input)\n    .with(\n      { type: 'post', user: { name: P.select('name') }, content: P.select('body') },\n      ({ name, body }) => `${name} wrote \"${body}\"`\n    )\n    .otherwise(() => '');\n\nconsole.log(output);\n// => 'Gabriel wrote \"Hello!\"'\n```\n\nYou can also pass a sub-pattern to `P.select` if you want it to only\nselect values which match this sub-pattern:\n\n```ts\ntype User = { age: number; name: string };\ntype Post = { body: string };\ntype Input = { author: User; content: Post };\n\ndeclare const input: Input;\n\nconst output = match(input)\n  .with(\n    {\n      author: P.select({ age: P.number.gt(18) }),\n    },\n    (author) => author // author: User\n  )\n  .with(\n    {\n      author: P.select('author', { age: P.number.gt(18) }),\n      content: P.select(),\n    },\n    ({ author, content }) => author // author: User, content: Post\n  )\n  .otherwise(() => 'anonymous');\n```\n\n### `P.optional` patterns\n\n`P.optional(subpattern)` lets you annotate a key in an object pattern as being optional,\nbut if it is defined it should match a given sub-pattern.\n\n```ts\nimport { match, P } from 'ts-pattern';\n\ntype Input = { key?: string | number };\n\nconst output = match(input)\n  .with({ key: P.optional(P.string) }, (a) => {\n    return a.key; // string | undefined\n  })\n  .with({ key: P.optional(P.number) }, (a) => {\n    return a.key; // number | undefined\n  })\n  .exhaustive();\n```\n\n### `P.instanceOf` patterns\n\nThe `P.instanceOf` function lets you build a pattern to check if\na value is an instance of a class:\n\n```ts\nimport { match, P } from 'ts-pattern';\n\nclass A {\n  a = 'a';\n}\nclass B {\n  b = 'b';\n}\n\ntype Input = { value: A | B };\n\nconst input: Input = { value: new A() };\n\nconst output = match(input)\n  .with({ value: P.instanceOf(A) }, (a) => {\n    return 'instance of A!';\n  })\n  .with({ value: P.instanceOf(B) }, (b) => {\n    return 'instance of B!';\n  })\n  .exhaustive();\n\nconsole.log(output);\n// => 'instance of A!'\n```\n\n### `P.union` patterns\n\n`P.union(...subpatterns)` lets you test several patterns and will match if\none of these patterns do. It's particularly handy when you want to handle\nsome cases of a union type in the same code branch:\n\n```ts\nimport { match, P } from 'ts-pattern';\n\ntype Input =\n  | { type: 'user'; name: string }\n  | { type: 'org'; name: string }\n  | { type: 'text'; content: string }\n  | { type: 'img'; src: string };\n\ndeclare const input: Input;\n\nconst output = match(input)\n  .with({ type: P.union('user', 'org') }, (userOrOrg) => {\n    // userOrOrg: User | Org\n    return userOrOrg.name;\n  })\n  .otherwise(() => '');\n```\n\n### `P.intersection` patterns\n\n`P.intersection(...subpatterns)` lets you ensure that the input matches\n**all** sub-patterns passed as parameters.\n\n```ts\nclass A {\n  constructor(public foo: 'bar' | 'baz') {}\n}\n\nclass B {\n  constructor(public str: string) {}\n}\n\ntype Input = { prop: A | B };\n\ndeclare const input: Input;\n\nconst output = match(input)\n  .with(\n    { prop: P.intersection(P.instanceOf(A), { foo: 'bar' }) },\n    ({ prop }) => prop.foo // prop: A & { foo: 'bar' }\n  )\n  .with(\n    { prop: P.intersection(P.instanceOf(A), { foo: 'baz' }) },\n    ({ prop }) => prop.foo // prop: A & { foo: 'baz' }\n  )\n  .otherwise(() => '');\n```\n\n## `P.string` predicates\n\n`P.string` has a number of methods to help you match on specific strings.\n\n### `P.string.startsWith`\n\n`P.string.startsWith(str)` matches strings that start with the provided string.\n\n```ts\nconst fn = (input: string) =>\n  match(input)\n    .with(P.string.startsWith('TS'), () => '🎉')\n    .otherwise(() => '❌');\n\nconsole.log(fn('TS-Pattern')); // logs '🎉'\n```\n\n### `P.string.endsWith`\n\n`P.string.endsWith(str)` matches strings that end with the provided string.\n\n```ts\nconst fn = (input: string) =>\n  match(input)\n    .with(P.string.endsWith('!'), () => '🎉')\n    .otherwise(() => '❌');\n\nconsole.log(fn('Hola!')); // logs '🎉'\n```\n\n### `P.string.minLength`\n\n`P.string.minLength(min)` matches strings with at least `min` characters.\n\n```ts\nconst fn = (input: string) =>\n  match(input)\n    .with(P.string.minLength(2), () => '🎉')\n    .otherwise(() => '❌');\n\nconsole.log(fn('two')); // logs '🎉'\n```\n\n### `P.string.length`\n\n`P.string.length(len)` matches strings with exactly `len` characters.\n\n```ts\nconst fn = (input: string) =>\n  match(input)\n    .with(P.string.length(2), () => '🎉')\n    .otherwise(() => '❌');\n\nconsole.log(fn('ok')); // logs '🎉'\n```\n\n### `P.string.maxLength`\n\n`P.string.maxLength(max)` matches strings with at most `max` characters.\n\n```ts\nconst fn = (input: string) =>\n  match(input)\n    .with(P.string.maxLength(5), () => '🎉')\n    .otherwise(() => 'too long');\n\nconsole.log(fn('is this too long?')); // logs 'too long'\n```\n\n### `P.string.includes`\n\n`P.string.includes(str)` matches strings that contain the provided substring.\n\n```ts\nconst fn = (input: string) =>\n  match(input)\n    .with(P.string.includes('!'), () => '✅')\n    .otherwise(() => '❌');\n\nconsole.log(fn('Good job! 🎉')); // logs '✅'\n```\n\n### `P.string.regex`\n\n`P.string.regex(RegExp)` matches strings if they match the provided regular expression.\n\n```ts\nconst fn = (input: string) =>\n  match(input)\n    .with(P.string.regex(/^[a-z]+$/), () => 'single word')\n    .otherwise(() => 'other strings');\n\nconsole.log(fn('gabriel')); // logs 'single word'\n```\n\n## `P.number` and `P.bigint` predicates\n\n`P.number` and `P.bigint` have several of methods to help you match on specific numbers and bigints.\n\n### `P.number.between`\n\n`P.number.between(min, max)` matches numbers between `min` and `max`.\n\n```ts\nconst fn = (input: number) =>\n  match(input)\n    .with(P.number.between(1, 5), () => '✅')\n    .otherwise(() => '❌');\n\nconsole.log(fn(3), fn(1), fn(5), fn(7)); // logs '✅ ✅ ✅ ❌'\n```\n\n### `P.number.lt`\n\n`P.number.lt(max)` matches numbers smaller than `max`.\n\n```ts\nconst fn = (input: number) =>\n  match(input)\n    .with(P.number.lt(7), () => '✅')\n    .otherwise(() => '❌');\n\nconsole.log(fn(2), fn(7)); // logs '✅ ❌'\n```\n\n### `P.number.gt`\n\n`P.number.gt(min)` matches numbers greater than `min`.\n\n```ts\nconst fn = (input: number) =>\n  match(input)\n    .with(P.number.gt(7), () => '✅')\n    .otherwise(() => '❌');\n\nconsole.log(fn(12), fn(7)); // logs '✅ ❌'\n```\n\n### `P.number.lte`\n\n`P.number.lte(max)` matches numbers smaller than or equal to `max`.\n\n```ts\nconst fn = (input: number) =>\n  match(input)\n    .with(P.number.lte(7), () => '✅')\n    .otherwise(() => '❌');\n\nconsole.log(fn(7), fn(12)); // logs '✅ ❌'\n```\n\n### `P.number.gte`\n\n`P.number.gte(min)` matches numbers greater than or equal to `min`.\n\n```ts\nconst fn = (input: number) =>\n  match(input)\n    .with(P.number.gte(7), () => '✅')\n    .otherwise(() => '❌');\n\nconsole.log(fn(7), fn(2)); // logs '✅ ❌'\n```\n\n### `P.number.int`\n\n`P.number.int()` matches integers.\n\n```ts\nconst fn = (input: number) =>\n  match(input)\n    .with(P.number.int(), () => '✅')\n    .otherwise(() => '❌');\n\nconsole.log(fn(12), fn(-3.141592)); // logs '✅ ❌'\n```\n\n### `P.number.finite`\n\n`P.number.finite()` matches all numbers except `Infinity` and `-Infinity`.\n\n```ts\nconst fn = (input: number) =>\n  match(input)\n    .with(P.number.finite(), () => '✅')\n    .otherwise(() => '❌');\n\nconsole.log(fn(-3.141592), fn(Infinity)); // logs '✅ ❌'\n```\n\n### `P.number.positive`\n\n`P.number.positive()` matches positive numbers.\n\n```ts\nconst fn = (input: number) =>\n  match(input)\n    .with(P.number.positive(), () => '✅')\n    .otherwise(() => '❌');\n\nconsole.log(fn(7), fn(-3.141592)); // logs '✅ ❌'\n```\n\n### `P.number.negative`\n\n`P.number.negative()` matches negative numbers.\n\n```ts\nconst fn = (input: number) =>\n  match(input)\n    .with(P.number.negative(), () => '✅')\n    .otherwise(() => '❌');\n\nconsole.log(fn(-3.141592), fn(7)); // logs '✅ ❌'\n```\n\n## Types\n\n### `P.infer`\n\n`P.infer<typeof somePattern>` lets you infer a type of value from a type of pattern.\n\nIt's particularly useful when validating an API response.\n\n```ts\nconst postPattern = {\n  title: P.string,\n  content: P.string,\n  stars: P.number.between(1, 5).optional(),\n  author: {\n    firstName: P.string,\n    lastName: P.string.optional(),\n    followerCount: P.number,\n  },\n} as const;\n\ntype Post = P.infer<typeof postPattern>;\n\n// posts: Post[]\nconst posts = await fetch(someUrl)\n  .then((res) => res.json())\n  .then((res: unknown): Post[] =>\n    isMatching({ data: P.array(postPattern) }, res) ? res.data : []\n  );\n```\n\nAlthough not strictly necessary, using `as const` after the pattern definition ensures that TS-Pattern infers the most precise types possible.\n\n### `P.narrow`\n\n`P.narrow<Input, typeof Pattern>` will narrow the input type to only keep the set of values that are compatible with the provided pattern type.\n\n```ts\ntype Input = ['a' | 'b' | 'c', 'a' | 'b' | 'c'];\nconst Pattern = ['a', P.union('a', 'b')] as const;\n\ntype Narrowed = P.narrow<Input, typeof Pattern>;\n//     ^? ['a', 'a' | 'b']\n```\n\nNote that most of the time, the `match` and `isMatching` functions perform narrowing for you, and you do not need to narrow types yourself.\n\n### `P.Pattern`\n\n`P.Pattern<T>` is the type of all possible pattern for a generic type `T`.\n\n```ts\ntype User = { name: string; age: number };\n\nconst userPattern: Pattern<User> = {\n  name: 'Alice',\n};\n```\n\n### Type inference\n\nTS-Pattern takes advantage the most advanced features of TypeScript to perform type narrowing and accurate exhaustive matching, even when matching on complex data-structures.\n\nHere are some examples of TS-Pattern's type inference features.\n\n#### Type narrowing\n\nWhen pattern-matching on a input containing union types, TS-Pattern will infer the most precise type possible for the argument of your handler function using the pattern you provide.\n\n```ts\ntype Text = { type: 'text'; data: string };\ntype Img = { type: 'img'; data: { src: string; alt: string } };\ntype Video = { type: 'video'; data: { src: string; format: 'mp4' | 'webm' } };\ntype Content = Text | Img | Video;\n\nconst formatContent = (content: Content): string =>\n  match(content)\n    .with({ type: 'text' }, (text /* : Text */) => '<p>...</p>')\n    .with({ type: 'img' }, (img /* : Img */) => '<img ... />')\n    .with({ type: 'video' }, (video /* : Video */) => '<video ... />')\n    .with(\n      { type: 'img' },\n      { type: 'video' },\n      (video /* : Img | Video */) => 'img or video'\n    )\n    .with(\n      { type: P.union('img', 'video') },\n      (video /* : Img | Video */) => 'img or video'\n    )\n    .exhaustive();\n```\n\nWhen using `P.select` in a pattern, TS-Pattern will find and inject the selected value in your handler. The type of your handler's argument is inferred accordingly.\n\n```ts\nconst formatContent = (content: Content): string =>\n  match(content)\n    .with(\n      { type: 'text', data: P.select() },\n      (content /* : string */) => '<p>...</p>'\n    )\n    .with(\n      { type: 'video', data: { format: P.select() } },\n      (format /* : 'mp4' | 'webm' */) => '<video ... />'\n    )\n    .with(\n      { type: P.union('img', 'video'), data: P.select() },\n      (data /* : Img['data'] | Video['data'] */) => 'img or video'\n    )\n    .exhaustive();\n```\n\n#### Type guard function\n\nIf you pass a [type guard](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates) function to `P.when`, TS-Pattern will use its return type to narrow the input.\n\n```ts\nconst isString = (x: unknown): x is string => typeof x === 'string';\n\nconst isNumber = (x: unknown): x is number => typeof x === 'number';\n\nconst fn = (input: { id: number | string }) =>\n  match(input)\n    .with({ id: P.when(isString) }, (narrowed /* : { id: string } */) => 'yes')\n    .with({ id: P.when(isNumber) }, (narrowed /* : { id: number } */) => 'yes')\n    .exhaustive();\n```\n\n#### Exhaustiveness checking\n\nTS-Pattern will keep track of handled and unhandled cases of your input type. Even when pattern-matching on several union types at once, you only need to call `.exhaustive()` to make sure that all possible cases are correctly handled.\n\n```ts\ntype Permission = 'editor' | 'viewer';\ntype Plan = 'basic' | 'pro';\n\nconst fn = (org: Plan, user: Permission): string =>\n  match([org, user])\n    .with(['basic', 'viewer'], () => {})\n    .with(['basic', 'editor'], () => {})\n    .with(['pro', 'viewer'], () => {})\n    // Fails with `NonExhaustiveError<['pro', 'editor']>`\n    // because the `['pro', 'editor']` case isn't handled.\n    .exhaustive();\n```\n\n## Inspirations\n\nThis library has been heavily inspired by this great article by Wim Jongeneel:\n[Pattern Matching in TypeScript with Record and Wildcard Patterns](https://medium.com/swlh/pattern-matching-in-typescript-with-record-and-wildcard-patterns-6097dd4e471d).\nIt made me realize pattern matching could be implemented in userland and we didn't have\nto wait for it to be added to the language itself. I'm really grateful for that 🙏\n"
  },
  {
    "path": "benchmarks/always-last-digit.ts",
    "content": "import { add, complete, cycle, suite } from 'benny';\nimport { match } from '../src';\n\ntype Digit = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;\n\nconst testExhaustive = (digit: Digit) => {\n  return match(digit)\n    .with(0, () => 'zero')\n    .with(1, () => 'one')\n    .with(2, () => 'two')\n    .with(3, () => 'three')\n    .with(4, () => 'four')\n    .with(5, () => 'five')\n    .with(6, () => 'six')\n    .with(7, () => 'seven')\n    .with(8, () => 'eight')\n    .with(9, () => 'nine')\n    .exhaustive();\n};\n\nconst testOtherwise = (digit: Digit) => {\n  return match(digit)\n    .with(0, () => 'zero')\n    .with(1, () => 'one')\n    .with(2, () => 'two')\n    .with(3, () => 'three')\n    .with(4, () => 'four')\n    .with(5, () => 'five')\n    .with(6, () => 'six')\n    .with(7, () => 'seven')\n    .with(8, () => 'eight')\n    .with(9, () => 'nine')\n    .otherwise(() => '');\n};\n\nconst testIfElse = (digit: Digit) => {\n  if (digit === 0) {\n    return 'zero';\n  } else if (digit === 1) {\n    return 'one';\n  } else if (digit === 2) {\n    return 'two';\n  } else if (digit === 3) {\n    return 'three';\n  } else if (digit === 4) {\n    return 'four';\n  } else if (digit === 5) {\n    return 'five';\n  } else if (digit === 6) {\n    return 'six';\n  } else if (digit === 7) {\n    return 'seven';\n  } else if (digit === 8) {\n    return 'eight';\n  } else if (digit === 9) {\n    return 'nine';\n  } else {\n    return '';\n  }\n};\n\nconst testSwitch = (digit: Digit) => {\n  switch (digit) {\n    case 0:\n      return 'zero';\n    case 1:\n      return 'one';\n    case 2:\n      return 'two';\n    case 3:\n      return 'three';\n    case 4:\n      return 'four';\n    case 5:\n      return 'five';\n    case 6:\n      return 'six';\n    case 7:\n      return 'seven';\n    case 8:\n      return 'eight';\n    case 9:\n      return 'nine';\n    default:\n      return '';\n  }\n};\n\nconst testTernary = (digit: Digit) => {\n  return digit === 0\n    ? 'zero'\n    : digit === 1\n    ? 'one'\n    : digit === 2\n    ? 'two'\n    : digit === 3\n    ? 'three'\n    : digit === 4\n    ? 'four'\n    : digit === 5\n    ? 'five'\n    : digit === 6\n    ? 'six'\n    : digit === 7\n    ? 'seven'\n    : digit === 8\n    ? 'eight'\n    : digit === 9\n    ? 'nine'\n    : '';\n};\n\nsuite(\n  'ts-pattern-benchmark',\n  add('.exhaustive()', () => testExhaustive(9)),\n  add('.otherwise()', () => testOtherwise(9)),\n  add('if/else', () => testIfElse(9)),\n  add('switch', () => testSwitch(9)),\n  add('ternary', () => testTernary(9)),\n  cycle(),\n  complete()\n);\n"
  },
  {
    "path": "benchmarks/nested-objects.ts",
    "content": "import { add, complete, cycle, suite } from 'benny';\nimport { P, match } from '../src';\n\nconst testExhaustive = (input: unknown) => {\n  return match(input)\n    .with({ type: 'a', value: { x: P.number, y: P.number } }, () => '1')\n    .with({ type: 'b', value: [1, ...P.array(P.number)] }, () => '2')\n    .with({ type: 'c', name: P.string, age: P.number }, () => '3')\n    .otherwise(() => '4');\n};\n\nconst testIfElse = (input: unknown) => {\n  if (\n    input &&\n    typeof input === 'object' &&\n    'type' in input &&\n    input.type === 'a' &&\n    'value' in input &&\n    input.value &&\n    typeof input.value === 'object' &&\n    'x' in input.value &&\n    typeof input.value.x === 'number' &&\n    'y' in input.value &&\n    typeof input.value.y === 'number'\n  ) {\n    return '1';\n  } else if (\n    input &&\n    typeof input === 'object' &&\n    'type' in input &&\n    input.type === 'b' &&\n    'value' in input &&\n    Array.isArray(input.value) &&\n    input.value[0] === 1 &&\n    input.value.slice(1).every((x) => typeof x === 'number')\n  ) {\n    return '2';\n  } else if (\n    input &&\n    typeof input === 'object' &&\n    'type' in input &&\n    input.type === 'c' &&\n    'name' in input &&\n    typeof input.name === 'string' &&\n    'age' in input &&\n    typeof input.age === 'number'\n  ) {\n    return '3';\n  } else {\n    return '4';\n  }\n};\n\nconst rand = () => {\n  const map = {\n    0: { type: 'a' as const, value: { x: Math.random(), y: Math.random() } },\n    1: {\n      type: 'b' as const,\n      value: Math.random() > 0.5 ? [1, 2, 3, 4] : ['hello'],\n    },\n    2: { type: 'c' as const, age: Math.random(), name: 'acdfl' },\n  };\n\n  return map[Math.floor(Math.random() * 3) as 0 | 1 | 2];\n};\n\nsuite(\n  'ts-pattern-benchmark',\n  add('.exhaustive()', () => testExhaustive(rand())),\n  add('if/else', () => testIfElse(rand())),\n  cycle(),\n  complete()\n);\n"
  },
  {
    "path": "benchmarks/package.json",
    "content": "{\n  \"name\": \"ts-pattern-benchmarks\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"test\": \"npm run always-last-digit && npm run random-digit && npm run nested-objects\",\n    \"always-last-digit\": \"bun run ./always-last-digit.ts\",\n    \"random-digit\": \"bun run ./random-digit.ts\",\n    \"nested-objects\": \"bun run ./nested-objects.ts\"\n  },\n  \"author\": \"\",\n  \"license\": \"ISC\",\n  \"devDependencies\": {\n    \"benny\": \"^3.7.1\",\n    \"bun\": \"^1.1.30\",\n    \"ts-pattern\": \"^5.0.5\"\n  }\n}"
  },
  {
    "path": "benchmarks/random-digit.ts",
    "content": "import { add, complete, cycle, suite } from 'benny';\nimport { match } from '../src';\n\ntype Digit = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;\n\nconst testExhaustive = (digit: Digit) => {\n  return match(digit)\n    .with(0, () => 'zero')\n    .with(1, () => 'one')\n    .with(2, () => 'two')\n    .with(3, () => 'three')\n    .with(4, () => 'four')\n    .with(5, () => 'five')\n    .with(6, () => 'six')\n    .with(7, () => 'seven')\n    .with(8, () => 'eight')\n    .with(9, () => 'nine')\n    .exhaustive();\n};\n\nconst testOtherwise = (digit: Digit) => {\n  return match(digit)\n    .with(0, () => 'zero')\n    .with(1, () => 'one')\n    .with(2, () => 'two')\n    .with(3, () => 'three')\n    .with(4, () => 'four')\n    .with(5, () => 'five')\n    .with(6, () => 'six')\n    .with(7, () => 'seven')\n    .with(8, () => 'eight')\n    .with(9, () => 'nine')\n    .otherwise(() => '');\n};\n\nconst testIfElse = (digit: Digit) => {\n  if (digit === 0) {\n    return 'zero';\n  } else if (digit === 1) {\n    return 'one';\n  } else if (digit === 2) {\n    return 'two';\n  } else if (digit === 3) {\n    return 'three';\n  } else if (digit === 4) {\n    return 'four';\n  } else if (digit === 5) {\n    return 'five';\n  } else if (digit === 6) {\n    return 'six';\n  } else if (digit === 7) {\n    return 'seven';\n  } else if (digit === 8) {\n    return 'eight';\n  } else if (digit === 9) {\n    return 'nine';\n  } else {\n    return '';\n  }\n};\n\nconst testSwitch = (digit: Digit) => {\n  switch (digit) {\n    case 0:\n      return 'zero';\n    case 1:\n      return 'one';\n    case 2:\n      return 'two';\n    case 3:\n      return 'three';\n    case 4:\n      return 'four';\n    case 5:\n      return 'five';\n    case 6:\n      return 'six';\n    case 7:\n      return 'seven';\n    case 8:\n      return 'eight';\n    case 9:\n      return 'nine';\n    default:\n      return '';\n  }\n};\n\nconst testTernary = (digit: Digit) => {\n  return digit === 0\n    ? 'zero'\n    : digit === 1\n    ? 'one'\n    : digit === 2\n    ? 'two'\n    : digit === 3\n    ? 'three'\n    : digit === 4\n    ? 'four'\n    : digit === 5\n    ? 'five'\n    : digit === 6\n    ? 'six'\n    : digit === 7\n    ? 'seven'\n    : digit === 8\n    ? 'eight'\n    : digit === 9\n    ? 'nine'\n    : '';\n};\n\nconst rand = () => Math.floor(Math.random() * 10) as Digit;\n\nsuite(\n  'ts-pattern-benchmark',\n  add('.exhaustive()', () => testExhaustive(rand())),\n  add('.otherwise()', () => testOtherwise(rand())),\n  add('if/else', () => testIfElse(rand())),\n  add('switch', () => testSwitch(rand())),\n  add('ternary', () => testTernary(rand())),\n  cycle(),\n  complete()\n);\n"
  },
  {
    "path": "docs/roadmap.md",
    "content": "### Roadmap\n\n- [ ] `P.ExactPattern<Type>` to infer the exact pattern you must write to fully cover all possible properties of `Type`.\n- [ ] Allow calling `isMatching` with a type parameter to restrain the pattern type: `isMatching<Type>(pattern)`.\n- [ ] better variant attempt.\n- [ ] `.narrow()` as an opt-in option to narrow the input type after a `.with`\n- [ ] `P.array.includes(x)`\n- [ ] `P.record({Pkey}, {Pvalue})`\n- [ ] `P.record`\n- [ ] `P.unknown` alias to any.\n- [x] `P.nonNullable`\n- [x] chainable methods\n  - [x] string\n    - [x] `P.string.includes('str')`\n    - [x] `P.string.startsWith('str')`\n    - [x] `P.string.endsWith('str')`\n    - [x] `P.string.regex('[a-z]+')`\n  - [x] numbers\n    - [x] `P.number.between(1, 10)`\n    - [x] `P.number.lt(12)`\n    - [x] `P.number.gt(12)`\n    - [x] `P.number.gte(12)`\n    - [x] `P.number.lte(12)`\n    - [x] `P.number.int(12)`\n    - [x] `P.number.finite`\n    - [x] `P.number.positive`\n    - [x] `P.number.negative`\n  - [x] all\n    - [x] `P.number.optional`\n    - [x] `P.string.optional`\n    - [x] `P.number.select()`\n    - [x] `P.string.select()`\n    - [x] `P.number.optional.select()`\n    - [x] `P.string.optional.select()`\n- [x] Add a custom matcher protocol data structures could implement to make them matchable.\n- [x] (Maybe) add an iterator protocol to `P.array` to be usable as a variadic tuple pattern. Example of using `P.array`:\n\n```ts\nconst reverse = <T>(xs: T[]): T[] => {\n  return match<T[], T[]>(xs)\n    .with([P.any, ...P.array()], ([x, ...xs]) => [...reverse(xs), x])\n    .otherwise(() => []);\n};\n\nmatch(xs)\n  .with([P.any, ...P.array()], (xs: [unknown, ...unknown[]]) => [])\n  .with([42, ...P.array(P.number), '!'], (xs: [42, ...number[], '!']) => [])\n  .with(\n    [...P.array(P.number), ...P.array(P.string)],\n    (xs: [...number[], ...string[]]) => []\n  )\n  .otherwise(() => []);\n```\n\n- [x] update `select()` and `select('name')` to accept a pattern the selected value should match.\n- [x] add a `union(...patterns)` pattern.\n- [x] When not provided, maybe compute the output type from all branches\n- [x] maybe add a lightweight `select` API for single values\n- [x] add support matching against several patterns in a single `.with()` clause.\n- [x] Find a way to enforce exhaustive pattern matching\n- [x] Several pattern/when clauses if necessary, with refined type inference from one to the other\n- [x] Find a way to make the full type inference work\n- [x] Add an operator to select a part of the data structure\n- [x] Add `not(value)` in patterns.\n- [x] Narrow down to type of value in `when` if the predicate is a type guard.\n"
  },
  {
    "path": "docs/v3-to-v4-migration-guide.md",
    "content": "# TS-Pattern v3 to v4 Migration Guide\n\n## Breaking changes\n\n### Imports\n\ntype-specific wildcard patterns have moved from `__.<pattern>` to a new `Pattern` qualified module, also exported as `P` by ts-pattern.\n\n```diff\n- import { match, __ } from 'ts-pattern';\n+ import { match, Pattern } from 'ts-pattern';\n\n\nconst toString = (value: string | number) =>\n  match(value)\n-   .with(__.string, (v) => v)\n-   .with(__.number, (v) => `${v}`)\n+   .with(Pattern.string, (v) => v)\n+   .with(Pattern.number, (v) => `${v}`)\n    .exhaustive();\n```\n\nor\n\n```diff\n- import { match, __ } from 'ts-pattern';\n+ import { match, P } from 'ts-pattern';\n\n\nconst toString = (value: string | number) =>\n  match(value)\n-   .with(__.string, (v) => v)\n-   .with(__.number, (v) => `${v}`)\n+   .with(P.string, (v) => v)\n+   .with(P.number, (v) => `${v}`)\n    .exhaustive();\n```\n\n#### `__`\n\nThe top level `__` export was moved to `P._` and `P.any`:\n\n```diff\n- import { match, __ } from 'ts-pattern';\n+ import { match, P } from 'ts-pattern';\n\n\nconst toString = (value: string | number) =>\n  match(value)\n-   .with(__, (v) => `${v}`)\n+   .with(P._, (v) => `${v}`)\n    // OR\n+   .with(P.any, (v) => `${v}`)\n    .exhaustive();\n```\n\n#### `select()`, `not()`, `when()`\n\nFunction to create patterns have been moved to the `P` module.\n\n```diff\n- import { match, select, not, when } from 'ts-pattern';\n+ import { match, P } from 'ts-pattern';\n\n\nconst toString = (value: number) =>\n  match(value)\n-   .with({ prop: select() }, (v) => `${v}`)\n+   .with({ prop: P.select() }, (v) => `${v}`)\n\n-   .with({ prop: not(10) }, (v) => `${v}`)\n+   .with({ prop: P.not(10) }, (v) => `${v}`)\n\n-   .with({ prop: when((x) => x < 5) }, (v) => `${v}`)\n+   .with({ prop: P.when((x) => x < 5) }, (v) => `${v}`)\n    .exhaustive();\n```\n\n#### `Pattern` type\n\nthe `Pattern` type which used to be exported at the toplevel is now accessible at `P.Pattern`.\n\n```diff\n- import { match, Pattern } from 'ts-pattern';\n+ import { match, P } from 'ts-pattern';\n\n- const pattern: Pattern<number> = P.when(x => x > 2);\n+ const pattern: P.Pattern<number> = P.when(x => x > 2);\n```\n\n### list patterns\n\nThe syntax for matching on a list of elements with an unknown length has changed from `[subpattern]` to `P.array(subpattern)`.\n\nExample:\n\n```diff\n- import { match, __ } from 'ts-pattern';\n+ import { match, P } from 'ts-pattern';\n\n\nconst parseUsers = (response: unknown) =>\n  match(response)\n-   .with({ data: [{ name: __.string }] }, (users) => users)\n+   .with({ data: P.array({ name: P.string }) }, (users) => users)\n    .otherwise(() => []);\n```\n\nNow `[subpattern]` matches arrays with 1 element in them. This is more consistent with native language features, like destructuring assignment and is overall more intuitive. This will resolve [#69](https://github.com/gvergnaud/ts-pattern/issues/69), [#62](https://github.com/gvergnaud/ts-pattern/issues/62) and [#46](https://github.com/gvergnaud/ts-pattern/issues/46).\n\n### NaN\n\nThe `__.NaN` pattern has been replaced by simply using the NaN value in the pattern:\n\n```diff\nmatch<number>(NaN)\n-   .with(__.NaN, () => \"this is not a number\")\n+   .with(NaN, () => \"this is not a number\")\n    .otherwise((n) => n);\n```\n\n## New features\n\nHere is the list of all new features which have been added in TS-Pattern v4.\n\n### Arrays and unary tuples\n\n#### `P.array(pattern)`\n\nTo match an array of elements, you can now use `P.array`:\n\n```ts\nimport { match, P } from 'ts-pattern';\n\nconst responsePattern = {\n  data: P.array({\n    id: P.string,\n    post: P.array({\n      title: P.string,\n      content: P.string,\n    }),\n  }),\n};\n\nfetchSomething().then((value: unknown) =>\n  match(value)\n    .with(responsePattern, (value) => {\n      // value: { data: { id: string, post: { title: string, content: string }[] }[] }\n      return value;\n    })\n    .otherwise(() => {\n      throw new Error('unexpected response');\n    })\n);\n```\n\n### Optional object properties\n\n#### `P.optional(pattern)`\n\nIf you want one of the keys of your pattern to be optional, you can now use `P.optional(subpattern)`.\n\nIf you `P.select()` something in an optional pattern, it's type will be infered as `T | undefined`.\n\n```ts\nimport { match, P } from 'ts-pattern';\n\nconst doSomethingWithUser = (user: User | Org) =>\n  match(user)\n    .with(\n      {\n        type: 'user',\n        detail: {\n          bio: P.optional(P.string),\n          socialLinks: P.optional({\n            twitter: P.select(),\n          }),\n        },\n      },\n      (twitterLink, value) => {\n        // twitterLink: string | undefined\n        /**\n         *  value.detail: {\n         *      bio?: string,\n         *      socialLinks?: {\n         *          twitter: string\n         *      }\n         *  }\n         **/\n      }\n    )\n    .otherwise(() => {\n      throw new Error('unexpected response');\n    });\n```\n\n### Union & intersection patterns\n\n`P.union(...patterns)` and `P.intersection(...patterns)` combine several patterns into a single one, either by checking that one of them match the input (`p.union`) or all of them match it (`P.intersection`).\n\n#### `P.union(...patterns)`\n\n```ts\ntype Input =\n  | { type: 'a'; value: string }\n  | { type: 'b'; value: number }\n  | {\n      type: 'c';\n      value:\n        | { type: 'd'; value: boolean }\n        | { type: 'e'; value: string[] }\n        | { type: 'f'; value: number[] };\n    };\n\nconst f = (input: Input) =>\n  match(input)\n    .with(\n      { type: P.union('a', 'b') },\n      // x: { type: 'a'; value: string } | { type: 'b'; value: number }\n      (x) => 'branch 1'\n    )\n    .with(\n      // P.union can take any subpattern:\n      {\n        type: 'c',\n        value: { value: P.union(P.boolean, P.array(P.string)) },\n      },\n      (x) => 'branch 2' // x.value.value: boolean | string[]\n    )\n    .with({ type: 'c', value: { type: 'f' } }, () => 'branch 3')\n    .exhaustive();\n```\n\n#### `P.intersection(...patterns)`\n\n```ts\nclass A {\n  constructor(public foo: 'bar' | 'baz') {}\n}\n\nclass B {\n  constructor(public str: string) {}\n}\n\nconst f = (input: { prop: A | B }) =>\n  match(input)\n    .with(\n      { prop: P.intersection(P.instanceOf(A), { foo: 'bar' }) },\n      // prop: A & { foo: 'bar' }\n      ({ prop }) => 'branch 1'\n    )\n    .with(\n      { prop: P.intersection(P.instanceOf(A), { foo: 'baz' }) },\n      // prop: A & { foo: 'baz' }\n      ({ prop }) => 'branch 2'\n    )\n    .with(\n      { prop: P.instanceOf(B) },\n      // prop: B\n      ({ prop }) => 'branch 3'\n    )\n    .exhaustive();\n```\n\n### Select with sub pattern\n\n`P.select()` now can take a subpattern and match only what the subpattern matches:\n\n```ts\ntype Img = { type: 'img'; src: string };\ntype Text = { type: 'text'; content: string; length: number };\ntype User = { type: 'user'; username: string };\ntype Org = { type: 'org'; orgId: number };\n\nconst post = (input: { author: User | Org; content: Text | Img }) =>\n  match(input)\n    .with(\n      { author: P.select({ type: 'user' }) },\n      // user: User\n      (user) => {}\n    )\n    .with(\n      {\n        // This also works with named selections\n        author: P.select('org', { type: 'org' }),\n        content: P.select('text', { type: 'text' }),\n      },\n      // org: Org, text: Text\n      ({ org, text }) => {}\n    )\n    .otherwise(() => {\n      // ...\n    });\n```\n\n### Infer the matching types from a pattern\n\n#### `P.infer<typeof pattern>`\n\nTS-Pattern is pretty handy for parsing unknown payloads like HTTP responses. You can write a pattern for the shape you are expecting, and then use `isMatching(pattern, response)` to make sure the response has the correct shape.\n\nOne limitation TS-Pattern had in its previous version was that it did not provide a way to get the TypeScript type of the value a given pattern matches. This is what `P.infer<typeof pattern>` does :)\n\n```ts\nconst postPattern = {\n  title: P.string,\n  description: P.optional(P.string),\n  content: P.string,\n  likeCount: P.number,\n};\n\ntype Post = P.infer<typeof postPattern>;\n// Post: { title: string, description?: string, content: string, likeCount: number }\n\nconst userPattern = {\n  name: P.string,\n  postCount: P.number,\n  bio: P.optional(P.string),\n  posts: P.optional(P.array(postPattern)),\n};\n\ntype User = P.infer<typeof userPattern>;\n// User: { name: string, postCount: number, bio?: string, posts?: Post[]  }\n\nconst isUserList = isMatching(P.array(userPattern));\n\nconst res = await fetchUsers();\n\nif (isUserList(res)) {\n  // res: User\n}\n```\n\n### New type specific wildcards\n\n#### `P.symbol`\n\n`P.symbol` is a wildcard pattern matching any **symbol**.\n\n```ts\nmatch(Symbol('Hello'))\n  .with(P.symbol, () => 'this is a symbol!')\n  .exhaustive();\n```\n\n#### `P.bigint`\n\n`P.bigint` is a wildcard pattern matching any **bigint**.\n\n```ts\nmatch(200n)\n  .with(P.bigint, () => 'this is a bigint!')\n  .exhaustive();\n```\n"
  },
  {
    "path": "docs/v4-to-v5-migration-guide.md",
    "content": "# TS-Pattern v4 to v5 Migration Guide\n\nThis file contains all breaking changes and new features between the version 4 and 5 of TS-Pattern.\n\n# Breaking changes\n\n## TypeScript v5\n\nBecause it relies on [const type parameters](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-0.html#const-type-parameters), TS-Pattern v5 requires TypeScript v5+!\n\n## `.with` is now evaluated eagerly\n\nIn the previous version of TS-Pattern, no code would execute until you called `.exhaustive()` or `.otherwise(...)`. For example, in the following code block, nothing would be logged to the console or thrown:\n\n```ts\n// TS-Pattern v4\ntype Input = { type: 'ok'; value: number } | { type: 'error'; error: Error };\n\n// We don't call `.exhaustive`, so handlers don't run.\nfunction someFunction(input: Input) {\n  match(input)\n    .with({ type: 'ok' }, ({ value }) => {\n      console.log(value);\n    })\n    .with({ type: 'error' }, ({ error }) => {\n      throw error;\n    });\n}\n\nsomeFunction({ type: 'ok', value: 42 }); // nothing happens\n```\n\nIn **TS-Pattern v5**, however, the library will execute the matching handler as soon as it finds it:\n\n```ts\n// TS-Pattern v5\nsomeFunction({ type: 'ok', value: 42 }); // logs \"42\" to the console!\n```\n\nHandlers are now evaluated **eagerly** instead of lazily. In practice, this shouldn't change anything as long as you always finish your pattern matching expressions by either `.exhaustive` or `.otherwise`.\n\n## Matching on Map and Sets\n\nMatching `Set` and `Map` instances using `.with(new Set(...))` and `.with(new Map(...))` is no longer supported. If you want to match specific sets and maps, you should now use the `P.map(keyPattern, valuePattern)` and `P.set(valuePattern)` patterns:\n\n```diff\n- import { match } from 'ts-pattern';\n+ import { match, P } from 'ts-pattern';\n\n\nconst someFunction = (value: Set<number> | Map<string, number>) =>\n  match(value)\n-   .with(new Set([P.number]), (set) => `a set of numbers`)\n-   .with(new Map([['key', P.number]]), (map) => `map.get('key') is a number`)\n+   .with(P.set(P.number), (set) => `a set of numbers`)\n+   .with(P.map('key', P.number), (map) => `map.get('key') is a number`)\n    .otherwise(() => null);\n```\n\n- The subpattern we provide in `P.set(subpattern)` should match all values in the Set.\n- The key and value subpatterns we provide in `P.map(keyPattern, subpattern)` should match all keys and values in the Map.\n\n# New features\n\n## chainable methods\n\nTS-Pattern v5's major addition is the ability to chain methods to narrow down the values matched by primitive patterns, like `P.string` or `P.number`.\n\nSince a few examples is worth a thousand words, here are a few ways you can use chainable methods:\n\n### P.number methods\n\n```ts\nconst example = (position: { x: number; y: number }) =>\n  match(position)\n    .with({ x: P.number.gte(100) }, (value) => '🎮')\n    .with({ x: P.number.between(0, 100) }, (value) => '🎮')\n    .with(\n      {\n        x: P.number.positive().int(),\n        y: P.number.positive().int(),\n      },\n      (value) => '🎮'\n    )\n    .otherwise(() => 'x or y is negative');\n```\n\nHere is the full list of number methods:\n\n- `P.number.between(min, max)`: matches numbers between `min` and `max`.\n- `P.number.lt(max)`: matches numbers smaller than `max`.\n- `P.number.gt(min)`: matches numbers greater than `min`.\n- `P.number.lte(max)`: matches numbers smaller than or equal to `max`.\n- `P.number.gte(min)`: matches numbers greater than or equal to `min`.\n- `P.number.int()`: matches integers.\n- `P.number.finite()`: matches all numbers except `Infinity` and `-Infinity`\n- `P.number.positive()`: matches positive numbers.\n- `P.number.negative()`: matches negative numbers.\n\n### P.string methods\n\n```ts\nconst example = (query: string) =>\n  match(query)\n    .with(P.string.startsWith('SELECT'), (query) => `selection`)\n    .with(P.string.endsWith('FROM user'), (query) => `👯‍♂️`)\n    .with(P.string.includes('*'), () => 'contains a star')\n    // Methods can be chained:\n    .with(P.string.startsWith('SET').includes('*'), (query) => `🤯`)\n    .exhaustive();\n```\n\nHere is the full list of string methods:\n\n- `P.string.startsWith(str)`: matches strings that start with `str`.\n- `P.string.endsWith(str)`: matches strings that end with `str`.\n- `P.string.minLength(min)`: matches strings with at least `min` characters.\n- `P.string.maxLength(max)`: matches strings with at most `max` characters.\n- `P.string.includes(str)`: matches strings that contain `str`.\n- `P.string.regex(RegExp)`: matches strings if they match this regular expression.\n\n### Global methods\n\nSome methods are available for all primitive type patterns:\n\n- `P.{..}.optional()`: matches even if this property isn't present on the input object.\n- `P.{..}.select()`: injects the matched value into the handler function.\n- `P.{..}.and(pattern)`: matches if the current pattern **and** the provided pattern match.\n- `P.{..}.or(pattern)`: matches if either the current pattern **or** the provided pattern match.\n\n```ts\nconst example = (value: unknown) =>\n  match(value)\n    .with(\n      {\n        username: P.string,\n        displayName: P.string.optional(),\n      },\n      () => `{ username:string, displayName?: string }`\n    )\n    .with(\n      {\n        title: P.string,\n        author: { username: P.string.select() },\n      },\n      (username) => `author.username is ${username}`\n    )\n    .with(\n      P.instanceOf(Error).and({ source: P.string }),\n      () => `Error & { source: string }`\n    )\n    .with(P.string.or(P.number), () => `string | number`)\n    .otherwise(() => null);\n```\n\n## Variadic tuple patterns\n\nWith TS-Pattern, you are now able to create array (or more accurately tuple) pattern with a variable number of elements:\n\n```ts\nconst example = (value: unknown) =>\n  match(value)\n    .with(\n      // non-empty list of strings\n      [P.string, ...P.array(P.string)],\n      (value) => `value: [string, ...string[]]`\n    )\n    .otherwise(() => null);\n```\n\nArray patterns that include a `...P.array` are called **variadic tuple patterns**. You may only have a single `...P.array`, but as many fixed-index patterns as you want:\n\n```ts\nconst example = (value: unknown) =>\n  match(value)\n    .with(\n      [P.string, P.string, P.string, ...P.array(P.string)],\n      (value) => `value: [string, string, string, ...string[]]`\n    )\n    .with(\n      [P.string, P.string, ...P.array(P.string)],\n      (value) => `value: [string, string, ...string[]]`\n    )\n    .with([], (value) => `value: []`)\n    .otherwise(() => null);\n```\n\nFixed-index patterns can also be set **after** the `...P.array` variadic, or on both sides!\n\n```ts\nconst example = (value: unknown) =>\n  match(value)\n    .with(\n      [...P.array(P.number), P.string, P.number],\n      (value) => `value: [...number[], string, number]`\n    )\n    .with(\n      [P.boolean, ...P.array(P.string), P.number, P.symbol],\n      (value) => `value: [boolean, ...string[], number, symbol]`\n    )\n    .otherwise(() => null);\n```\n\nLastly, argument of `P.array` is now optional, and will default to `P._`, which matches anything:\n\n```ts\nconst example = (value: unknown) =>\n  match(value)\n    //                         👇\n    .with([P.string, ...P.array()], (value) => `value: [string, ...unknown[]]`)\n    .otherwise(() => null);\n```\n\n## `.returnType`\n\nIn TS-Pattern v4, the only way to explicitly set the return type of your `match` expression is to set the two `<Input, Output>` type parameters of `match`:\n\n```ts\n// TS-Pattern v4\nmatch<\n  { isAdmin: boolean; plan: 'free' | 'paid' }, // input type\n  number // return type\n>({ isAdmin, plan })\n  .with({ isAdmin: true }, () => 123)\n  .with({ plan: 'free' }, () => 'Oops!');\n//                              ~~~~~~ ❌ not a number.\n```\n\nthe main drawback is that you need to set the **_input type_** explicitly **_too_**, even though TypeScript should be able to infer it.\n\nIn TS-Pattern v5, you can use the `.returnType<Type>()` method to only set the return type:\n\n```ts\nmatch({ isAdmin, plan })\n  .returnType<number>() // 👈 new\n  .with({ isAdmin: true }, () => 123)\n  .with({ plan: 'free' }, () => 'Oops!');\n//                              ~~~~~~ ❌ not a number.\n```\n"
  },
  {
    "path": "examples/gif-fetcher/package.json",
    "content": "{\n  \"name\": \"ts-pattern-v4-gif-search-demo\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"keywords\": [],\n  \"main\": \"src/index.tsx\",\n  \"dependencies\": {\n    \"lodash\": \"^4.17.21\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"ts-pattern\": \"^5.5.0\"\n  },\n  \"devDependencies\": {\n    \"@types/lodash\": \"^4.17.0\",\n    \"@types/react\": \"^18.2.74\",\n    \"@types/react-dom\": \"^18.2.24\",\n    \"react-scripts\": \"^5.0.1\",\n    \"typescript\": \"^5.4.4\"\n  },\n  \"scripts\": {\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n    \"test\": \"react-scripts test --env=jsdom\",\n    \"eject\": \"react-scripts eject\"\n  }\n}"
  },
  {
    "path": "examples/gif-fetcher/public/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n    <title>TS-Pattern GIF Search Demo</title>\n  </head>\n  <body>\n    <div id=\"root\"></div>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/gif-fetcher/src/App.tsx",
    "content": "import { searchGif } from './searchGif';\nimport { throttle } from 'lodash';\nimport * as React from 'react';\nimport './styles.css';\n\nimport { match } from 'ts-pattern';\n\n/**\n * The shape of our application state.\n */\ntype State = {\n  query: string;\n  data:\n    | { status: 'idle' }\n    | { status: 'loading' }\n    | { status: 'success'; gifUrls: string[] }\n    | { status: 'error'; error: Error };\n};\n\n/**\n * The union of all events our application\n * can handle.\n */\ntype Event =\n  | { type: 'search'; query: string }\n  | { type: 'success'; query: string; gifUrls: string[] }\n  | { type: 'error'; query: string; error: Error }\n  | { type: 'cancel' };\n\n/**\n * Initial state of our GIF fetcher app\n */\nconst initState: State = {\n  query: '',\n  data: { status: 'idle' },\n};\n\n/**\n * All state transitions happen in this\n * reducer function\n */\nconst reducer = (state: State, event: Event): State =>\n  match<Event, State>(event)\n    .with({ type: 'search' }, ({ query }) => ({\n      query,\n      data: {\n        status: 'loading',\n      },\n    }))\n\n    .with({ type: 'cancel' }, () => ({\n      ...state,\n      data: { status: 'idle' },\n    }))\n\n    // only transition to success if `event.query`\n    // matches `state.query`\n    .with({ type: 'success', query: state.query }, ({ gifUrls }) => ({\n      ...state,\n      data: {\n        status: 'success',\n        gifUrls,\n      },\n    }))\n\n    // only transition to error if `event.query`\n    // matches `state.query`\n    .with({ type: 'error', query: state.query }, ({ error }) => ({\n      ...state,\n      data: { status: 'error', error },\n    }))\n\n    .otherwise(() => state);\n\nexport default function App() {\n  const [state, dispatch] = React.useReducer(reducer, initState);\n\n  React.useEffect(() => {\n    if (state.query) {\n      searchGif(state.query)\n        .then((urls) =>\n          dispatch({\n            type: 'success',\n            gifUrls: urls,\n            query: state.query,\n          })\n        )\n        .catch((error) =>\n          dispatch({\n            type: 'error',\n            error,\n            query: state.query,\n          })\n        );\n    } else {\n      dispatch({ type: 'cancel' });\n    }\n  }, [state.query]);\n\n  const onSearch = React.useCallback(\n    throttle(\n      (query: string) =>\n        dispatch({\n          type: 'search',\n          query,\n        }),\n      100\n    ),\n    []\n  );\n\n  return (\n    <div className=\"App\">\n      <input\n        placeholder=\"Search a GIF\"\n        onChange={(e) => onSearch(e.target.value)}\n      />\n      <div>\n        {match(state.data)\n          .with({ status: 'idle' }, () => (\n            <>\n              <h1>Idle</h1>\n              <p>Nothing is happening at the moment</p>\n            </>\n          ))\n          .with({ status: 'loading' }, () => (\n            <>\n              <h1>Loading...</h1>\n            </>\n          ))\n          .with({ status: 'success', gifUrls: [] }, () => (\n            <>\n              <h1>No results!</h1>\n            </>\n          ))\n          .with({ status: 'success' }, ({ gifUrls }) => (\n            <>\n              <h1>Fetch success!</h1>\n              <div className=\"img-grid\">\n                {gifUrls.map((url) => (\n                  <img key={url} src={url} alt=\"gif\" />\n                ))}\n              </div>\n            </>\n          ))\n          .with({ status: 'error' }, ({ error }) => (\n            <>\n              <h1>Fetch error!</h1>\n              <p>{error.message}</p>\n            </>\n          ))\n          .exhaustive()}\n      </div>\n    </div>\n  );\n}\n"
  },
  {
    "path": "examples/gif-fetcher/src/constants.ts",
    "content": "export const API_KEY = 'xxxxxxxxxxxxxxxx';\n"
  },
  {
    "path": "examples/gif-fetcher/src/index.tsx",
    "content": "import * as React from 'react';\nimport { render } from 'react-dom';\n\nimport App from './App';\n\nconst rootElement = document.getElementById('root');\nrender(<App />, rootElement);\n"
  },
  {
    "path": "examples/gif-fetcher/src/searchGif.ts",
    "content": "import { isMatching, P } from 'ts-pattern';\nimport { API_KEY } from './constants';\n\nconst delay = (ms: number) => new Promise((res) => setTimeout(res, ms));\n\nexport function searchGif(query: string) {\n  return fetch(\n    `https://api.giphy.com/v1/gifs/search?api_key=${API_KEY}&q=${query}&limit=25&offset=0&rating=g&lang=en`\n  )\n    .then((res) => res.json())\n    .then(async (res) => {\n      await delay(500);\n      return res;\n    })\n    .then((res: unknown) => {\n      if (\n        isMatching(\n          {\n            data: P.array({\n              images: {\n                fixed_height: {\n                  url: P.string,\n                },\n              },\n            }),\n          },\n          res\n        )\n      ) {\n        // Note how `isMatching` narrows the type of `res`:\n        return res.data.map(({ images }) => images.fixed_height.url);\n      } else {\n        throw new Error('Oh, no! The HTTP request failed.');\n      }\n    });\n}\n"
  },
  {
    "path": "examples/gif-fetcher/src/styles.css",
    "content": "body {\n  margin: 0;\n}\n\n* {\n  box-sizing: border-box;\n}\n\n.App {\n  margin: 10px;\n  font-family: sans-serif;\n  text-align: center;\n}\n\ninput {\n  display: block;\n  padding: 10px 15px;\n  width: 100%;\n}\n\nimg {\n  max-width: 100%;\n}\n\n.img-grid {\n  display: flex;\n  flex-wrap: wrap;\n  justify-content: center;\n}\n\n.img-grid > *:not(:first-child) {\n  padding-top: 10px;\n}\n\n.img-grid > *:not(:first-child) {\n  padding-left: 10px;\n}\n"
  },
  {
    "path": "examples/gif-fetcher/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true,\n    \"target\": \"es2022\",\n    \"allowJs\": true,\n    \"moduleResolution\": \"Bundler\",\n    \"resolveJsonModule\": true,\n    \"isolatedModules\": true,\n    \"strict\": true,\n    \"noUncheckedIndexedAccess\": true,\n    \"module\": \"ESNext\",\n    \"noEmit\": true,\n    \"jsx\": \"react\",\n    \"lib\": [\"es2022\", \"dom\", \"dom.iterable\"]\n  }\n}\n"
  },
  {
    "path": "examples/one-file-demo/one-file-demo.ts",
    "content": "import { isMatching, match, P } from 'ts-pattern';\n\n/**\n * ### One file TS-Pattern demo.\n *\n * This will demonstrate:\n * - How to use pattern matching and wildcards\n * - How to extract a value from the input Data Structure using `P.select`\n * - How to match several cases using `P.union`\n * - How to leverage exhaustiveness checking to make sure every case is handled\n * - How to pattern match on several values at once using tuples\n * - How to validate an unknown API response using `isMatching` and patterns like\n *   `P.array`, `P.optional`, etc.\n */\n\n/**************************************************\n * Use case 1: handling discriminated union types *\n **************************************************/\n\ntype Response =\n  | { type: 'video'; data: { format: 'mp4' | 'webm'; src: string } }\n  | { type: 'image'; data: { extension: 'gif' | 'jpg' | 'png'; src: string } }\n  | { type: 'text'; data: string; tags: { name: string; id: number }[] };\n\nconst example1 = (input: Response): string =>\n  match(input)\n    // 1. Basic pattern with inference with a wildcard\n    .with({ type: 'video', data: { format: 'mp4' } }, (video) => video.data.src)\n    // 2. using select\n    .with(\n      { type: 'image', data: { extension: 'gif', src: P.select() } },\n      (src) => `<img src=${src} alt=\"This is a gif!\" />`\n    )\n    // 3. using P.union\n    .with(\n      {\n        type: 'image',\n        data: { extension: P.union('jpg', 'png'), src: P.select() },\n      },\n      (src) => `<img src=${src} alt=\"This is a jpg or a png!\" />`\n    )\n    // 4. selecting all tag names with P.array and P.select\n    .with(\n      { type: 'text', tags: P.array({ name: P.select() }) },\n      (tagNames) => `text with tags: ${tagNames.join(', ')}`\n    )\n    // 5. basic exhaustiveness checking\n    // ⚠️ doesn't type-check!\n    // @ts-expect-error: { type: 'video', data: { format: 'webm' } } isn't covered\n    .exhaustive();\n\n/**************************************\n * Use case 2: multi params branching *\n **************************************/\n\ntype UserType = 'editor' | 'viewer';\n// Uncomment 'enterprise' to see exhaustive checking in action\ntype OrgPlan = 'basic' | 'pro' | 'premium'; // | 'enterprise';\n\nconst example2 = (org: OrgPlan, user: UserType) =>\n  // 1. Checking several enums with tuples\n  match([org, user])\n    .with(['basic', P._], () => `Please upgrade to unlock this feature!`)\n    // 2. `.with()` can take several patterns. It will match if one of them do.\n    .with(\n      ['pro', 'viewer'],\n      ['premium', 'viewer'],\n      () => `Your account doesn't have permissions to use this feature`\n    )\n    .with(['pro', 'editor'], () => `Hello!`)\n    .with(['premium', 'editor'], () => `You are our favorite customer!`)\n    // 3. complex exhaustive checking\n    .exhaustive();\n\n/**************************************************\n * Use case 3: Matching specific strings or numbers\n **************************************************/\n\nconst example3 = (queries: string[]) =>\n  match(queries)\n    .with(\n      [\n        P.string.startsWith('SELECT').endsWith('FROM user').select(),\n        ...P.array(),\n      ],\n      (firstQuery) => `${firstQuery}: 👨‍👩‍👧‍👦`\n    )\n    .with(P.array(), () => 'other queries')\n    .exhaustive();\n\nconst example4 = (position: { x: number; y: number }) =>\n  match(position)\n    .with({ x: P.number.gte(100) }, (value) => '⏱️')\n    .with({ x: P.number.between(0, 100) }, (value) => '⏱️')\n    .with({ x: P.number.positive(), y: P.number.positive() }, (value) => '⏱️')\n    .otherwise(() => 'x or y is negative');\n\n/******************************************\n * Use case 4: Validation an API response *\n ******************************************/\n\nconst User = {\n  name: P.string,\n  // 1. optional properties\n  age: P.number.optional(),\n  socialLinks: P.optional({\n    twitter: P.string,\n    instagram: P.string,\n  }),\n};\n\ntype User = P.infer<typeof User>;\n/*    ^? {\n    name: string;\n    age?: number | undefined;\n    socialLinks?: {\n        twitter: string;\n        instagram: string;\n    } | undefined;\n} */\n\nconst Post = {\n  title: P.string.minLength(2).maxLength(255),\n  stars: P.number.int().between(0, 5),\n  content: P.string,\n  author: User,\n  // 2. arrays\n  comments: P.array({ author: User, content: P.string }),\n  // 3. tuples (a non-empty array in this case)\n  tags: [P.string, ...P.array(P.string)],\n} as const;\n\ntype Post = P.infer<typeof Post>;\n/*    ^? {\n    author: User;\n    content: string;\n    title: string;\n    stars: number;\n    comments: { author: User; content: string }[];\n    tags: [string, ...string[]];\n} */\n\n// Elsewhere in the code:\n// `fetch(...).then(validateResponse)`\n\nconst validateResponse = (response: unknown): Post | null => {\n  // 3. validating unknown input with isMatching\n  if (isMatching(Post, response)) {\n    //  response is inferred as  `Post`.\n\n    // Uncomment these lines if you want to try using `response`:\n    // const cardTitle = `${response.title} by @${response.author.name}`;\n    // const commenters = response.comments.map((c) => c.author.name).join(', ');\n    return response;\n  }\n\n  return null;\n};\n"
  },
  {
    "path": "examples/one-file-demo/package.json",
    "content": "{\n  \"name\": \"ts-pattern-examples\",\n  \"version\": \"1.0.0\",\n  \"main\": \"one-file-demo.ts\",\n  \"author\": \"gvergnaud\",\n  \"dependencies\": {\n    \"ts-pattern\": \"^5.5.0\"\n  }\n}"
  },
  {
    "path": "examples/one-file-demo/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"strict\": true,\n    \"lib\": [\"ES2015\"],\n    \"target\": \"ES2015\",\n    \"moduleResolution\": \"bundler\",\n    \"module\": \"ESNext\"\n  }\n}\n"
  },
  {
    "path": "jest.config.cjs",
    "content": "module.exports = {\n  preset: 'ts-jest',\n  testEnvironment: 'node',\n};\n"
  },
  {
    "path": "jsr.json",
    "content": "{\n  \"name\": \"@gabriel/ts-pattern\",\n  \"version\": \"5.9.0\",\n  \"exports\": {\n    \".\": \"./src/index.ts\",\n    \"./types\": \"./src/index.ts\",\n    \"./package.json\": \"./package.json\"\n  }\n}"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"ts-pattern\",\n  \"version\": \"5.9.0\",\n  \"description\": \" The exhaustive Pattern Matching library for TypeScript.\",\n  \"type\": \"module\",\n  \"sideEffects\": false,\n  \"source\": \"src/index.ts\",\n  \"exports\": {\n    \".\": {\n      \"require\": {\n        \"types\": \"./dist/index.d.cts\",\n        \"default\": \"./dist/index.cjs\"\n      },\n      \"import\": {\n        \"types\": \"./dist/index.d.ts\",\n        \"default\": \"./dist/index.js\"\n      },\n      \"types\": \"./dist/index.d.ts\",\n      \"default\": \"./dist/index.js\"\n    },\n    \"./types\": {\n      \"require\": {\n        \"types\": \"./dist/types/index.d.cts\"\n      },\n      \"import\": {\n        \"types\": \"./dist/types/index.d.ts\"\n      },\n      \"types\": \"./dist/types/index.d.ts\"\n    },\n    \"./package.json\": \"./package.json\"\n  },\n  \"types\": \"dist/index.d.ts\",\n  \"main\": \"dist/index.cjs\",\n  \"module\": \"dist/index.js\",\n  \"unpkg\": \"dist/index.umd.js\",\n  \"scripts\": {\n    \"build\": \"rimraf dist && microbundle --format modern,cjs,umd && sh ./scripts/generate-cts.sh\",\n    \"dev\": \"microbundle watch\",\n    \"prepublishOnly\": \"npm run test && npm run build\",\n    \"publish:jsr\": \"npm run prepublishOnly && npx jsr publish\",\n    \"release\": \"npm run prepublishOnly && npm publish && npx jsr publish\",\n    \"test\": \"jest\",\n    \"clear-test\": \"jest --clearCache\",\n    \"fmt\": \"prettier ./src/** ./tests/** -w\",\n    \"check\": \"tsc --strict --noEmit --extendedDiagnostics\",\n    \"perf\": \"tsc --project tests/tsconfig.json --noEmit --extendedDiagnostics\",\n    \"trace\": \"tsc --project tests/tsconfig.json --generateTrace trace --incremental false  --noEmit\",\n    \"analyzeTrace\": \"npx @typescript/analyze-trace trace\"\n  },\n  \"files\": [\n    \"dist/**/*\",\n    \"package.json\"\n  ],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+ssh://git@github.com/gvergnaud/ts-pattern.git\"\n  },\n  \"keywords\": [\n    \"pattern\",\n    \"matching\",\n    \"pattern-matching\",\n    \"typescript\",\n    \"match-with\",\n    \"match\",\n    \"switch\",\n    \"adt\"\n  ],\n  \"author\": \"Gabriel Vergnaud\",\n  \"license\": \"MIT\",\n  \"bugs\": {\n    \"url\": \"https://github.com/gvergnaud/ts-pattern/issues\"\n  },\n  \"homepage\": \"https://github.com/gvergnaud/ts-pattern#readme\",\n  \"devDependencies\": {\n    \"@types/jest\": \"^30.0.0\",\n    \"jest\": \"^30.1.3\",\n    \"microbundle\": \"^0.15.1\",\n    \"prettier\": \"^2.8.8\",\n    \"rimraf\": \"^5.0.1\",\n    \"ts-jest\": \"^29.4.1\",\n    \"typescript\": \"^5.9.2\"\n  }\n}\n"
  },
  {
    "path": "scripts/generate-cts.sh",
    "content": "#!/bin/bash\n\n# TypeScript projects using `moduleResolution: nodenext` expect\n# explicit extensions to be included in declaration files,\n# and to have a different set of declarations for commonjs\n# modules (.d.cts) and ES modules (.d.ts). `tsc` unfortunately\n# doesn't provide a way to generate these declarations files,\n# so I'm manually creating them in this script.\n\nfiles=$(find dist -type f -name \"*.d.ts\");\n\n# Loop through the declaration files\nfor file in $files; do\n    # Update imports to include the '.cjs' extension\n    sed -E \"s/(.*)from '([^']*)'/\\1from '\\2.cjs'/g\" \"$file\" > \"${file%.d.ts}.d.cts\"\n    # add `.js` extensions to .d.ts files\n    sed -i '' -e \"s/\\(.*\\)from '\\([^']*\\)'/\\1from '\\2.js'/g\" \"$file\"\ndone"
  },
  {
    "path": "src/errors.ts",
    "content": "/**\n * Error when the given input value does not match any included pattern\n * and .exhaustive() was specified\n */\nexport class NonExhaustiveError extends Error {\n  constructor(public input: unknown) {\n    let displayedValue;\n    try {\n      displayedValue = JSON.stringify(input);\n    } catch (e) {\n      displayedValue = input;\n    }\n    super(`Pattern matching error: no pattern matches value ${displayedValue}`);\n  }\n}\n"
  },
  {
    "path": "src/index.ts",
    "content": "import * as Pattern from './patterns';\n\nexport { match } from './match';\nexport { isMatching } from './is-matching';\nexport { Pattern, Pattern as P };\nexport { NonExhaustiveError } from './errors';\n"
  },
  {
    "path": "src/internals/helpers.ts",
    "content": "/**\n * @module\n * @private\n * @internal\n */\n\nimport * as symbols from './symbols';\nimport { SelectionType } from '../types/FindSelected';\nimport { Pattern, Matcher, MatcherType, AnyMatcher } from '../types/Pattern';\n\n// @internal\nexport const isObject = (value: unknown): value is Object =>\n  Boolean(value && typeof value === 'object');\n\n//   @internal\nexport const isMatcher = (\n  x: unknown\n): x is Matcher<unknown, unknown, MatcherType, SelectionType> => {\n  const pattern = x as Matcher<unknown, unknown, MatcherType, SelectionType>;\n  return pattern && !!pattern[symbols.matcher];\n};\n\n// @internal\nconst isOptionalPattern = (\n  x: unknown\n): x is Matcher<unknown, unknown, 'optional', SelectionType> => {\n  return isMatcher(x) && x[symbols.matcher]().matcherType === 'optional';\n};\n\n// tells us if the value matches a given pattern.\n// @internal\nexport const matchPattern = (\n  pattern: any,\n  value: any,\n  select: (key: string, value: unknown) => void\n): boolean => {\n  if (isMatcher(pattern)) {\n    const matcher = pattern[symbols.matcher]();\n    const { matched, selections } = matcher.match(value);\n    if (matched && selections) {\n      Object.keys(selections).forEach((key) => select(key, selections[key]));\n    }\n    return matched;\n  }\n\n  if (isObject(pattern)) {\n    if (!isObject(value)) return false;\n\n    // Tuple pattern\n    if (Array.isArray(pattern)) {\n      if (!Array.isArray(value)) return false;\n      let startPatterns = [];\n      let endPatterns = [];\n      let variadicPatterns: AnyMatcher[] = [];\n\n      for (const i of pattern.keys()) {\n        const subpattern = pattern[i];\n        if (isMatcher(subpattern) && subpattern[symbols.isVariadic]) {\n          variadicPatterns.push(subpattern);\n        } else if (variadicPatterns.length) {\n          endPatterns.push(subpattern);\n        } else {\n          startPatterns.push(subpattern);\n        }\n      }\n\n      if (variadicPatterns.length) {\n        if (variadicPatterns.length > 1) {\n          throw new Error(\n            `Pattern error: Using \\`...P.array(...)\\` several times in a single pattern is not allowed.`\n          );\n        }\n\n        if (value.length < startPatterns.length + endPatterns.length) {\n          return false;\n        }\n\n        const startValues = value.slice(0, startPatterns.length);\n        const endValues =\n          endPatterns.length === 0 ? [] : value.slice(-endPatterns.length);\n        const middleValues = value.slice(\n          startPatterns.length,\n          endPatterns.length === 0 ? Infinity : -endPatterns.length\n        );\n\n        return (\n          startPatterns.every((subPattern, i) =>\n            matchPattern(subPattern, startValues[i], select)\n          ) &&\n          endPatterns.every((subPattern, i) =>\n            matchPattern(subPattern, endValues[i], select)\n          ) &&\n          (variadicPatterns.length === 0\n            ? true\n            : matchPattern(variadicPatterns[0], middleValues, select))\n        );\n      }\n\n      return pattern.length === value.length\n        ? pattern.every((subPattern, i) =>\n            matchPattern(subPattern, value[i], select)\n          )\n        : false;\n    }\n\n    return Reflect.ownKeys(pattern).every((k): boolean => {\n      const subPattern = pattern[k];\n\n      return (\n        (k in value || isOptionalPattern(subPattern)) &&\n        matchPattern(subPattern, value[k], select)\n      );\n    });\n  }\n\n  return Object.is(value, pattern);\n};\n\n// @internal\nexport const getSelectionKeys = (pattern: any): string[] => {\n  if (isObject(pattern)) {\n    if (isMatcher(pattern)) {\n      return pattern[symbols.matcher]().getSelectionKeys?.() ?? [];\n    }\n    if (Array.isArray(pattern)) return flatMap(pattern, getSelectionKeys);\n    return flatMap(Object.values(pattern), getSelectionKeys);\n  }\n  return [];\n};\n\n// @internal\nexport const flatMap = <a, b>(\n  xs: readonly a[],\n  f: (v: a) => readonly b[]\n): b[] => xs.reduce<b[]>((acc, x) => acc.concat(f(x)), []);\n"
  },
  {
    "path": "src/internals/symbols.ts",
    "content": "/**\n * Symbols used internally within ts-pattern to construct and discriminate\n * Guard, Not, and Select, and AnonymousSelect patterns\n *\n * Symbols have the advantage of not appearing in auto-complete suggestions in\n * user defined patterns, and eliminate the risk of property\n * overlap between ts-pattern internals and user defined patterns.\n *\n * These symbols have to be visible to tsc for type inference to work, but\n * users should not import them\n * @module\n * @private\n * @internal\n */\n\nexport const matcher = Symbol.for('@ts-pattern/matcher');\nexport type matcher = typeof matcher;\n\nexport const unset = Symbol.for('@ts-pattern/unset');\nexport type unset = typeof unset;\n\nexport const isVariadic = Symbol.for('@ts-pattern/isVariadic');\nexport type isVariadic = typeof isVariadic;\n\n// can't be a symbol because this key has to be enumerable.\nexport const anonymousSelectKey = '@ts-pattern/anonymous-select-key';\nexport type anonymousSelectKey = typeof anonymousSelectKey;\n\nexport const override = Symbol.for('@ts-pattern/override');\nexport type override = typeof override;\n"
  },
  {
    "path": "src/is-matching.ts",
    "content": "import { MatchedValue, Pattern, UnknownProperties } from './types/Pattern';\nimport * as P from './patterns';\nimport { matchPattern } from './internals/helpers';\nimport { WithDefault } from './types/helpers';\n\n/**\n * This constraint allows using additional properties\n * in object patterns. See \"should allow targetting unknown properties\"\n * unit test in `is-matching.test.ts`.\n */\ntype PatternConstraint<T> = T extends readonly any[]\n  ? P.Pattern<T>\n  : T extends object\n  ? P.Pattern<T> & UnknownProperties\n  : P.Pattern<T>;\n\n/**\n * `isMatching` takes pattern and returns a **type guard** function, cheching if a value matches this pattern.\n *\n * [Read  documentation for `isMatching` on GitHub](https://github.com/gvergnaud/ts-pattern#ismatching)\n *\n * @example\n *  const hasName = isMatching({ name: P.string })\n *\n *  declare let input: unknown\n *\n *  if (hasName(input)) {\n *    // `input` inferred as { name: string }\n *    return input.name\n *  }\n */\nexport function isMatching<const p extends Pattern<unknown>>(\n  pattern: p\n): (value: unknown) => value is P.infer<p>;\n/**\n * `isMatching` takes pattern and a value and checks if the value matches this pattern.\n *\n * [Read  documentation for `isMatching` on GitHub](https://github.com/gvergnaud/ts-pattern#ismatching)\n *\n * @example\n *  declare let input: unknown\n *\n *  if (isMatching({ name: P.string }, input)) {\n *    // `input` inferred as { name: string }\n *    return input.name\n *  }\n */\nexport function isMatching<const T, const P extends PatternConstraint<T>>(\n  pattern: P,\n  value: T\n): value is T & WithDefault<P.narrow<T, P>, P.infer<P>>;\n\nexport function isMatching<const p extends Pattern<any>>(\n  ...args: [pattern: p, value?: any]\n): boolean | ((vale: any) => boolean) {\n  if (args.length === 1) {\n    const [pattern] = args;\n    return (value: any): value is MatchedValue<any, P.infer<p>> =>\n      matchPattern(pattern, value, () => {});\n  }\n  if (args.length === 2) {\n    const [pattern, value] = args;\n    return matchPattern(pattern, value, () => {});\n  }\n\n  throw new Error(\n    `isMatching wasn't given the right number of arguments: expected 1 or 2, received ${args.length}.`\n  );\n}\n"
  },
  {
    "path": "src/match.ts",
    "content": "import { Pattern } from './types/Pattern';\nimport { Match } from './types/Match';\nimport * as symbols from './internals/symbols';\nimport { matchPattern } from './internals/helpers';\nimport { NonExhaustiveError } from './errors';\n\ntype MatchState<output> =\n  | { matched: true; value: output }\n  | { matched: false; value: undefined };\n\nconst unmatched: MatchState<never> = {\n  matched: false,\n  value: undefined,\n};\n\n/**\n * `match` creates a **pattern matching expression**.\n *  * Use `.with(pattern, handler)` to pattern match on the input.\n *  * Use `.exhaustive()` or `.otherwise(() => defaultValue)` to end the expression and get the result.\n *\n * [Read the documentation for `match` on GitHub](https://github.com/gvergnaud/ts-pattern#match)\n *\n * @example\n *  declare let input: \"A\" | \"B\";\n *\n *  return match(input)\n *    .with(\"A\", () => \"It's an A!\")\n *    .with(\"B\", () => \"It's a B!\")\n *    .exhaustive();\n *\n */\nexport function match<const input, output = symbols.unset>(\n  value: input\n): Match<input, output> {\n  return new MatchExpression(value, unmatched) as any;\n}\n\n/**\n * This class represents a match expression. It follows the\n * builder pattern, we chain methods to add features to the expression\n * until we call `.exhaustive`, `.otherwise` or the unsafe `.run`\n * method to execute it.\n *\n * The types of this class aren't public, the public type definition\n * can be found in src/types/Match.ts.\n */\nclass MatchExpression<input, output> {\n  constructor(private input: input, private state: MatchState<output>) {}\n\n  with(...args: any[]): MatchExpression<input, output> {\n    if (this.state.matched) return this;\n\n    const handler: (selection: unknown, value: input) => output =\n      args[args.length - 1];\n\n    const patterns: Pattern<input>[] = [args[0]];\n    let predicate: ((value: input) => unknown) | undefined = undefined;\n\n    if (args.length === 3 && typeof args[1] === 'function') {\n      // case with guard as second argument\n      predicate = args[1];\n    } else if (args.length > 2) {\n      // case with several patterns\n      patterns.push(...args.slice(1, args.length - 1));\n    }\n\n    let hasSelections = false;\n    let selected: Record<string, unknown> = {};\n    const select = (key: string, value: unknown) => {\n      hasSelections = true;\n      selected[key] = value;\n    };\n\n    const matched =\n      patterns.some((pattern) => matchPattern(pattern, this.input, select)) &&\n      (predicate ? Boolean(predicate(this.input)) : true);\n\n    const selections = hasSelections\n      ? symbols.anonymousSelectKey in selected\n        ? selected[symbols.anonymousSelectKey]\n        : selected\n      : this.input;\n\n    const state = matched\n      ? {\n          matched: true as const,\n          value: handler(selections, this.input),\n        }\n      : unmatched;\n\n    return new MatchExpression(this.input, state);\n  }\n\n  when(\n    predicate: (value: input) => unknown,\n    handler: (selection: input, value: input) => output\n  ): MatchExpression<input, output> {\n    if (this.state.matched) return this;\n\n    const matched = Boolean(predicate(this.input));\n\n    return new MatchExpression<input, output>(\n      this.input,\n      matched\n        ? { matched: true, value: handler(this.input, this.input) }\n        : unmatched\n    );\n  }\n\n  otherwise(handler: (value: input) => output): output {\n    if (this.state.matched) return this.state.value;\n    return handler(this.input);\n  }\n\n  exhaustive(unexpectedValueHandler = defaultCatcher): output {\n    if (this.state.matched) return this.state.value;\n    return unexpectedValueHandler(this.input);\n  }\n\n  run(): output {\n    return this.exhaustive();\n  }\n\n  returnType() {\n    return this;\n  }\n\n  narrow() {\n    return this;\n  }\n}\n\nfunction defaultCatcher(input: unknown): never {\n  throw new NonExhaustiveError(input);\n}\n"
  },
  {
    "path": "src/patterns.ts",
    "content": "/**\n * The `P` module contains patterns for primitive types, wildcards and\n * other pattern-matching utilities.\n *\n * @module\n */\n\nimport { matchPattern, getSelectionKeys, flatMap } from './internals/helpers';\nimport * as symbols from './internals/symbols';\nimport { matcher } from './internals/symbols';\nimport { isMatching } from './is-matching';\nimport { ExtractPreciseValue } from './types/ExtractPreciseValue';\nimport { Fn } from './types/helpers';\nimport { InvertPattern } from './types/InvertPattern';\nimport {\n  Pattern,\n  UnknownValuePattern,\n  OptionalP,\n  ArrayP,\n  MapP,\n  SetP,\n  AndP,\n  OrP,\n  NotP,\n  GuardP,\n  SelectP,\n  AnonymousSelectP,\n  GuardExcludeP,\n  CustomP,\n  Matcher,\n  StringPattern,\n  UnknownPattern,\n  NumberPattern,\n  BooleanPattern,\n  BigIntPattern,\n  NullishPattern,\n  SymbolPattern,\n  Chainable,\n  BigIntChainable,\n  NumberChainable,\n  StringChainable,\n  ArrayChainable,\n  Variadic,\n  NonNullablePattern,\n  RecordP,\n} from './types/Pattern';\n\nexport type {\n  /**\n   * `Pattern<T>` is the type of all patterns\n   * that can match a value of type `T`.\n   */\n  Pattern,\n\n  /**\n   * `unstable_Fn` can be used to created a\n   * a Matchable instance – a custom type that\n   * can be used as a pattern.\n   *\n   * @experimental This feature is unstable.\n   */\n  Fn as unstable_Fn,\n};\n\nexport { matcher };\n\n/**\n * A `Matchable` is an object implementing\n * the Matcher Protocol. It must have a `[P.matcher]: P.Matcher<NarrowFn>`\n * key, which defines how this object should be matched by TS-Pattern.\n *\n * @experimental This feature is unstable.\n *\n * @example\n * ```ts\n * class Some<T> implements P.unstable_Matchable {\n *  [P.matcher](): P.unstable_Matcher<Some<T>>\n * }\n * ```\n */\nexport type unstable_Matchable<\n  narrowedOrFn,\n  input = unknown,\n  pattern = never\n> = CustomP<input, pattern, narrowedOrFn>;\n\n/**\n * A `Matcher` is an object with `match` function, which\n * defines how this object should be matched by TS-Pattern.\n *\n * @experimental This feature is unstable.\n *\n * @example\n * ```ts\n * class Some<T> implements P.unstable_Matchable {\n *  [P.matcher](): P.unstable_Matcher<Some<T>>\n * }\n * ```\n */\nexport type unstable_Matcher<\n  narrowedOrFn,\n  input = unknown,\n  pattern = never\n> = ReturnType<CustomP<input, pattern, narrowedOrFn>[matcher]>;\n\n/**\n * `P.infer<typeof somePattern>` will return the type of the value\n * matched by this pattern.\n *\n * [Read the documentation for `P.infer` on GitHub](https://github.com/gvergnaud/ts-pattern#pinfer)\n *\n * @example\n * const userPattern = { name: P.string }\n * type User = P.infer<typeof userPattern>\n */\nexport type infer<pattern> = InvertPattern<NoInfer<pattern>, unknown>;\n\n/**\n * `P.narrow<Input, Pattern>` will narrow the input type to only keep\n * the set of values that are compatible with the provided pattern type.\n *\n * [Read the documentation for `P.narrow` on GitHub](https://github.com/gvergnaud/ts-pattern#pnarrow)\n *\n * @example\n * type Input = ['a' | 'b' | 'c', 'a' | 'b' | 'c']\n * const Pattern = ['a', P.union('a', 'b')] as const\n *\n * type Narrowed = P.narrow<Input, typeof Pattern>\n * //     ^? ['a', 'a' | 'b']\n */\nexport type narrow<input, pattern> = ExtractPreciseValue<\n  input,\n  InvertPattern<pattern, input>\n>;\n\nfunction chainable<pattern extends Matcher<any, any, any, any, any>>(\n  pattern: pattern\n): Chainable<pattern> {\n  return Object.assign(pattern, {\n    optional: () => optional(pattern),\n    and: (p2: any) => intersection(pattern, p2),\n    or: (p2: any) => union(pattern, p2),\n    select: (key: any) =>\n      key === undefined ? select(pattern) : select(key, pattern),\n  }) as Chainable<pattern>;\n}\n\nconst variadic = <pattern extends {}>(pattern: pattern): Variadic<pattern> =>\n  Object.assign(pattern, {\n    [Symbol.iterator](): Iterator<pattern, void, undefined> {\n      let i = 0;\n      const variadicPattern = Object.assign(pattern, {\n        [symbols.isVariadic]: true,\n      });\n      const values: IteratorResult<pattern, void>[] = [\n        { value: variadicPattern, done: false },\n        { done: true, value: undefined },\n      ];\n      return {\n        next: () => values[i++] ?? values.at(-1)!,\n      };\n    },\n  });\n\nfunction arrayChainable<pattern extends Matcher<any, any, any, any, any>>(\n  pattern: pattern\n): ArrayChainable<pattern> {\n  return Object.assign(variadic(pattern), {\n    optional: () => arrayChainable(optional(pattern)),\n    select: (key: any) =>\n      arrayChainable(\n        key === undefined ? select(pattern) : select(key, pattern)\n      ),\n  }) as any;\n}\n\n/**\n * `P.optional(subpattern)` takes a sub pattern and returns a pattern which matches if the\n * key is undefined or if it is defined and the sub pattern matches its value.\n *\n * [Read the documentation for `P.optional` on GitHub](https://github.com/gvergnaud/ts-pattern#poptional-patterns)\n *\n * @example\n *  match(value)\n *   .with({ greeting: P.optional('Hello') }, () => 'will match { greeting?: \"Hello\" }')\n */\nexport function optional<\n  input,\n  const pattern extends unknown extends input\n    ? UnknownValuePattern\n    : Pattern<input>\n>(pattern: pattern): Chainable<OptionalP<input, pattern>, 'optional'> {\n  return chainable({\n    [matcher]() {\n      return {\n        match: <UnknownInput>(value: UnknownInput | input) => {\n          let selections: Record<string, unknown[]> = {};\n          const selector = (key: string, value: any) => {\n            selections[key] = value;\n          };\n          if (value === undefined) {\n            getSelectionKeys(pattern).forEach((key) =>\n              selector(key, undefined)\n            );\n            return { matched: true, selections };\n          }\n          const matched = matchPattern(pattern, value, selector);\n          return { matched, selections };\n        },\n        getSelectionKeys: () => getSelectionKeys(pattern),\n        matcherType: 'optional',\n      };\n    },\n  });\n}\n\ntype UnwrapArray<xs> = xs extends readonly (infer x)[] ? x : never;\n\ntype UnwrapSet<xs> = xs extends Set<infer x> ? x : never;\n\ntype UnwrapMapKey<xs> = xs extends Map<infer k, any> ? k : never;\n\ntype UnwrapMapValue<xs> = xs extends Map<any, infer v> ? v : never;\n\ntype UnwrapRecordKey<xs> = xs extends Record<infer k, any> ? k : never;\n\ntype UnwrapRecordValue<xs> = xs extends Record<any, infer v> ? v : never;\n\ntype WithDefault<a, b> = [a] extends [never] ? b : a;\n\n/**\n * `P.array(subpattern)` takes a sub pattern and returns a pattern, which matches\n * arrays if all their elements match the sub pattern.\n *\n * [Read the documentation for `P.array` on GitHub](https://github.com/gvergnaud/ts-pattern#parray-patterns)\n *\n * @example\n *  match(value)\n *   .with({ users: P.array({ name: P.string }) }, () => 'will match { name: string }[]')\n */\nexport function array<input>(): ArrayChainable<ArrayP<input, unknown>>;\nexport function array<\n  input,\n  const pattern extends Pattern<WithDefault<UnwrapArray<input>, unknown>>\n>(pattern: pattern): ArrayChainable<ArrayP<input, pattern>>;\nexport function array(\n  ...args: [pattern?: any]\n): ArrayChainable<ArrayP<any, any>> {\n  return arrayChainable({\n    [matcher]() {\n      return {\n        match: (value: any) => {\n          if (!Array.isArray(value)) return { matched: false };\n\n          if (args.length === 0) return { matched: true };\n\n          const pattern = args[0];\n          let selections: Record<string, unknown[]> = {};\n\n          if (value.length === 0) {\n            getSelectionKeys(pattern).forEach((key) => {\n              selections[key] = [];\n            });\n            return { matched: true, selections };\n          }\n\n          const selector = (key: string, value: unknown) => {\n            selections[key] = (selections[key] || []).concat([value]);\n          };\n\n          const matched = value.every((v) =>\n            matchPattern(pattern, v, selector)\n          );\n\n          return { matched, selections };\n        },\n        getSelectionKeys: () =>\n          args.length === 0 ? [] : getSelectionKeys(args[0]),\n      };\n    },\n  });\n}\n\n/**\n * `P.set(subpattern)` takes a sub pattern and returns a pattern that matches\n * sets if all their elements match the sub pattern.\n *\n * [Read `P.set` documentation on GitHub](https://github.com/gvergnaud/ts-pattern#pset-patterns)\n *\n * @example\n *  match(value)\n *   .with({ users: P.set(P.string) }, () => 'will match Set<string>')\n */\nexport function set<input>(): Chainable<SetP<input, unknown>>;\nexport function set<\n  input,\n  const pattern extends Pattern<WithDefault<UnwrapSet<input>, unknown>>\n>(pattern: pattern): Chainable<SetP<input, pattern>>;\nexport function set<\n  input,\n  const pattern extends Pattern<WithDefault<UnwrapSet<input>, unknown>>\n>(...args: [pattern?: pattern]): Chainable<SetP<input, pattern>> {\n  return chainable({\n    [matcher]() {\n      return {\n        match: <UnknownInput>(value: UnknownInput | input) => {\n          if (!(value instanceof Set)) return { matched: false };\n\n          let selections: Record<string, unknown[]> = {};\n\n          if (value.size === 0) {\n            return { matched: true, selections };\n          }\n\n          if (args.length === 0) return { matched: true };\n\n          const selector = (key: string, value: unknown) => {\n            selections[key] = (selections[key] || []).concat([value]);\n          };\n\n          const pattern = args[0];\n\n          const matched = setEvery(value, (v) =>\n            matchPattern(pattern, v, selector)\n          );\n\n          return { matched, selections };\n        },\n        getSelectionKeys: () =>\n          args.length === 0 ? [] : getSelectionKeys(args[0]),\n      };\n    },\n  });\n}\n\nconst setEvery = <T>(set: Set<T>, predicate: (value: T) => boolean) => {\n  for (const value of set) {\n    if (predicate(value)) continue;\n    return false;\n  }\n  return true;\n};\n\n/**\n * `P.map(keyPattern, valuePattern)` takes a subpattern to match against the\n * key, a subpattern to match against the value and returns a pattern that\n * matches on maps where all elements inside the map match those two\n * subpatterns.\n *\n * [Read `P.map` documentation on GitHub](https://github.com/gvergnaud/ts-pattern#pmap-patterns)\n *\n * @example\n *  match(value)\n *   .with({ users: P.map(P.string, P.number) }, (map) => `map's type is Map<string, number>`)\n */\nexport function map<input>(): Chainable<MapP<input, unknown, unknown>>;\nexport function map<\n  input,\n  const pkey extends Pattern<WithDefault<UnwrapMapKey<input>, unknown>>,\n  const pvalue extends Pattern<WithDefault<UnwrapMapValue<input>, unknown>>\n>(patternKey: pkey, patternValue: pvalue): Chainable<MapP<input, pkey, pvalue>>;\nexport function map<\n  input,\n  const pkey extends Pattern<WithDefault<UnwrapMapKey<input>, unknown>>,\n  const pvalue extends Pattern<WithDefault<UnwrapMapValue<input>, unknown>>\n>(\n  ...args: [patternKey?: pkey, patternValue?: pvalue]\n): Chainable<MapP<input, pkey, pvalue>> {\n  return chainable({\n    [matcher]() {\n      return {\n        match: <UnknownInput>(value: UnknownInput | input) => {\n          if (!(value instanceof Map)) return { matched: false };\n\n          let selections: Record<string, unknown[]> = {};\n\n          if (value.size === 0) {\n            return { matched: true, selections };\n          }\n\n          const selector = (key: string, value: unknown) => {\n            selections[key] = (selections[key] || []).concat([value]);\n          };\n\n          if (args.length === 0) return { matched: true };\n          if (args.length === 1) {\n            throw new Error(\n              `\\`P.map\\` wasn\\'t given enough arguments. Expected (key, value), received ${args[0]?.toString()}`\n            );\n          }\n          const [patternKey, patternValue] = args;\n\n          const matched = mapEvery(value, (v, k) => {\n            const keyMatch = matchPattern(patternKey, k, selector);\n            const valueMatch = matchPattern(patternValue, v, selector);\n            return keyMatch && valueMatch;\n          });\n\n          return { matched, selections };\n        },\n        getSelectionKeys: () =>\n          args.length === 0\n            ? []\n            : [...getSelectionKeys(args[0]), ...getSelectionKeys(args[1])],\n      };\n    },\n  });\n}\n\nconst mapEvery = <K, T>(\n  map: Map<K, T>,\n  predicate: (value: T, key: K) => boolean\n) => {\n  for (const [key, value] of map.entries()) {\n    if (predicate(value, key)) continue;\n    return false;\n  }\n  return true;\n};\n\n/**\n * `P.record(keyPattern, valuePattern)` takes a subpattern to match against the\n * key, a subpattern to match against the value and returns a pattern that\n * matches on objects where all entries match those two\n * subpatterns.\n *\n * [Read `P.record` documentation on GitHub](https://github.com/gvergnaud/ts-pattern#precord-patterns)\n *\n * @example\n *  match(value)\n *   .with({ users: P.record(P.string, P.number) }, (obj) => `object's type is Record<string, number>`)\n */\nexport function record<\n  input,\n  const pvalue extends Pattern<UnwrapRecordValue<input>>\n>(patternValue: pvalue): Chainable<RecordP<input, StringPattern, pvalue>>;\nexport function record<\n  input,\n  const pkey extends Pattern<WithDefault<UnwrapRecordKey<input>, PropertyKey>>,\n  const pvalue extends Pattern<WithDefault<UnwrapRecordValue<input>, unknown>>\n>(\n  patternKey: pkey,\n  patternValue?: pvalue\n): Chainable<RecordP<input, pkey, pvalue>>;\nexport function record(\n  ...args: [patternKey?: unknown, patternValue?: unknown]\n): Chainable<RecordP<unknown, unknown, unknown>> {\n  return chainable({\n    [matcher]() {\n      return {\n        match: (value: unknown) => {\n          if (\n            value === null ||\n            typeof value !== 'object' ||\n            Array.isArray(value)\n          ) {\n            return { matched: false };\n          }\n\n          if (args.length === 0) {\n            throw new Error(\n              `\\`P.record\\` wasn\\'t given enough arguments. Expected (value) or (key, value), received ${args[0]?.toString()}`\n            );\n          }\n\n          let selections: Record<string, unknown[]> = {};\n\n          const selector = (key: string, value: unknown) => {\n            selections[key] = (selections[key] || []).concat([value]);\n          };\n\n          const [patternKey, patternValue] =\n            args.length === 1 ? [string, args[0]] : args;\n\n          const matched = recordEvery(value, (k, v) => {\n            // since number keys are coerced to strings, we need to coerce them back to numbers if the pattern is `number`\n            const coercedKey =\n              typeof k === 'string' && !Number.isNaN(Number(k))\n                ? Number(k)\n                : null;\n\n            const coercedKeyMatch =\n              coercedKey !== null\n                ? matchPattern(patternKey, coercedKey, selector)\n                : false;\n\n            const keyMatch = matchPattern(patternKey, k, selector);\n\n            const valueMatch = matchPattern(patternValue, v, selector);\n\n            return (keyMatch || coercedKeyMatch) && valueMatch;\n          });\n\n          return { matched, selections };\n        },\n        getSelectionKeys: () =>\n          args.length === 0\n            ? []\n            : [...getSelectionKeys(args[0]), ...getSelectionKeys(args[1])],\n      };\n    },\n  });\n}\n\nconst recordEvery = <K extends PropertyKey, T>(\n  record: Record<K, T>,\n  predicate: (key: K, value: T) => boolean\n) => {\n  const keys = Reflect.ownKeys(record);\n  for (const key of keys) {\n    if (predicate(key as K, record[key as K] as T)) continue;\n    return false;\n  }\n  return true;\n};\n\n/**\n * `P.intersection(...patterns)` returns a pattern which matches\n * only if **every** patterns provided in parameter match the input.\n *\n * [Read the documentation for `P.intersection` on GitHub](https://github.com/gvergnaud/ts-pattern#pintersection-patterns)\n *\n * @example\n *  match(value)\n *   .with(\n *     {\n *       user: P.intersection(\n *         { firstname: P.string },\n *         { lastname: P.string },\n *         { age: P.when(age => age > 21) }\n *       )\n *     },\n *     ({ user }) => 'will match { firstname: string, lastname: string, age: number } if age > 21'\n *   )\n */\nexport function intersection<\n  input,\n  const patterns extends readonly [Pattern<input>, ...Pattern<input>[]]\n>(...patterns: patterns): Chainable<AndP<input, patterns>> {\n  return chainable({\n    [matcher]: () => ({\n      match: (value) => {\n        let selections: Record<string, unknown[]> = {};\n        const selector = (key: string, value: any) => {\n          selections[key] = value;\n        };\n        const matched = (patterns as readonly UnknownValuePattern[]).every(\n          (p) => matchPattern(p, value, selector)\n        );\n        return { matched, selections };\n      },\n      getSelectionKeys: () =>\n        flatMap(patterns as readonly UnknownValuePattern[], getSelectionKeys),\n      matcherType: 'and',\n    }),\n  });\n}\n\n/**\n * `P.union(...patterns)` returns a pattern which matches\n * if **at least one** of the patterns provided in parameter match the input.\n *\n * [Read the documentation for `P.union` on GitHub](https://github.com/gvergnaud/ts-pattern#punion-patterns)\n *\n * @example\n *  match(value)\n *   .with(\n *     { type: P.union('a', 'b', 'c') },\n *     ({ type }) => 'will match { type: \"a\" | \"b\" | \"c\" }'\n *   )\n */\nexport function union<\n  input,\n  const patterns extends readonly [Pattern<input>, ...Pattern<input>[]]\n>(...patterns: patterns): Chainable<OrP<input, patterns>> {\n  return chainable({\n    [matcher]: () => ({\n      match: <UnknownInput>(value: UnknownInput | input) => {\n        let selections: Record<string, unknown[]> = {};\n        const selector = (key: string, value: any) => {\n          selections[key] = value;\n        };\n        flatMap(\n          patterns as readonly UnknownValuePattern[],\n          getSelectionKeys\n        ).forEach((key) => selector(key, undefined));\n        const matched = (patterns as readonly UnknownValuePattern[]).some((p) =>\n          matchPattern(p, value, selector)\n        );\n        return { matched, selections };\n      },\n      getSelectionKeys: () =>\n        flatMap(patterns as readonly UnknownValuePattern[], getSelectionKeys),\n      matcherType: 'or',\n    }),\n  });\n}\n\n/**\n * `P.not(pattern)` returns a pattern which matches if the sub pattern\n * doesn't match.\n *\n * [Read the documentation for `P.not` on GitHub](https://github.com/gvergnaud/ts-pattern#pnot-patterns)\n *\n * @example\n *  match<{ a: string | number }>(value)\n *   .with({ a: P.not(P.string) }, (x) => 'will match { a: number }'\n *   )\n */\n\nexport function not<\n  input,\n  const pattern extends Pattern<input> | UnknownValuePattern\n>(pattern: pattern): Chainable<NotP<input, pattern>> {\n  return chainable({\n    [matcher]: () => ({\n      match: <UnknownInput>(value: UnknownInput | input) => ({\n        matched: !matchPattern(pattern, value, () => {}),\n      }),\n      getSelectionKeys: () => [],\n      matcherType: 'not',\n    }),\n  });\n}\n\n/**\n * `P.when((value) => boolean)` returns a pattern which matches\n * if the predicate returns true for the current input.\n *\n * [Read the documentation for `P.when` on GitHub](https://github.com/gvergnaud/ts-pattern#pwhen-patterns)\n *\n * @example\n *  match<{ age: number }>(value)\n *   .with({ age: P.when(age => age > 21) }, (x) => 'will match if value.age > 21'\n *   )\n */\nexport function when<input, predicate extends (value: input) => unknown>(\n  predicate: predicate\n): GuardP<\n  input,\n  predicate extends (value: any) => value is infer narrowed ? narrowed : never\n>;\nexport function when<input, narrowed extends input, excluded>(\n  predicate: (input: input) => input is narrowed\n): GuardExcludeP<input, narrowed, excluded>;\nexport function when<input, predicate extends (value: input) => unknown>(\n  predicate: predicate\n): GuardP<\n  input,\n  predicate extends (value: any) => value is infer narrowed ? narrowed : never\n> {\n  return {\n    [matcher]: () => ({\n      match: <UnknownInput>(value: UnknownInput | input) => ({\n        matched: Boolean(predicate(value as input)),\n      }),\n    }),\n  };\n}\n\n/**\n * `P.select()` is a pattern which will always match,\n * and will inject the selected piece of input in the handler function.\n *\n * [Read the documentation for `P.select` on GitHub](https://github.com/gvergnaud/ts-pattern#pselect-patterns)\n *\n * @example\n *  match<{ age: number }>(value)\n *   .with({ age: P.select() }, (age) => 'age: number'\n *   )\n */\nexport function select(): Chainable<AnonymousSelectP, 'select' | 'or' | 'and'>;\nexport function select<\n  input,\n  const patternOrKey extends\n    | string\n    | (unknown extends input ? UnknownValuePattern : Pattern<input>)\n>(\n  patternOrKey: patternOrKey\n): patternOrKey extends string\n  ? Chainable<SelectP<patternOrKey, 'select' | 'or' | 'and'>>\n  : Chainable<\n      SelectP<symbols.anonymousSelectKey, input, patternOrKey>,\n      'select' | 'or' | 'and'\n    >;\nexport function select<\n  input,\n  const pattern extends unknown extends input\n    ? UnknownValuePattern\n    : Pattern<input>,\n  const k extends string\n>(\n  key: k,\n  pattern: pattern\n): Chainable<SelectP<k, input, pattern>, 'select' | 'or' | 'and'>;\nexport function select(\n  ...args: [keyOrPattern?: unknown | string, pattern?: unknown]\n): Chainable<SelectP<string>, 'select' | 'or' | 'and'> {\n  const key: string | undefined =\n    typeof args[0] === 'string' ? args[0] : undefined;\n  const pattern: unknown =\n    args.length === 2\n      ? args[1]\n      : typeof args[0] === 'string'\n      ? undefined\n      : args[0];\n  return chainable({\n    [matcher]() {\n      return {\n        match: (value) => {\n          let selections: Record<string, unknown> = {\n            [key ?? symbols.anonymousSelectKey]: value,\n          };\n          const selector = (key: string, value: any) => {\n            selections[key] = value;\n          };\n          return {\n            matched:\n              pattern === undefined\n                ? true\n                : matchPattern(pattern, value, selector),\n            selections: selections,\n          };\n        },\n        getSelectionKeys: () =>\n          [key ?? symbols.anonymousSelectKey].concat(\n            pattern === undefined ? [] : getSelectionKeys(pattern)\n          ),\n      };\n    },\n  });\n}\n\nfunction isUnknown(x: unknown): x is unknown {\n  return true;\n}\n\nfunction isNumber<T>(x: T | number): x is number {\n  return typeof x === 'number';\n}\n\nfunction isString<T>(x: T | string): x is string {\n  return typeof x === 'string';\n}\n\nfunction isBoolean<T>(x: T | boolean): x is boolean {\n  return typeof x === 'boolean';\n}\n\nfunction isBigInt<T>(x: T | bigint): x is bigint {\n  return typeof x === 'bigint';\n}\n\nfunction isSymbol<T>(x: T | symbol): x is symbol {\n  return typeof x === 'symbol';\n}\n\nfunction isNullish<T>(x: T | null | undefined): x is null | undefined {\n  return x === null || x === undefined;\n}\n\nfunction isNonNullable(x: unknown): x is {} {\n  return x !== null && x !== undefined;\n}\n\ntype AnyConstructor = abstract new (...args: any[]) => any;\n\nfunction isInstanceOf<T extends AnyConstructor>(classConstructor: T) {\n  return (val: unknown): val is InstanceType<T> =>\n    val instanceof classConstructor;\n}\n\n/**\n * `P.any` is a wildcard pattern, matching **any value**.\n *\n * [Read the documentation for `P.any` on GitHub](https://github.com/gvergnaud/ts-pattern#p_-wildcard)\n *\n * @example\n *  match(value)\n *   .with(P.any, () => 'will always match')\n */\nexport const any: UnknownPattern = chainable(when(isUnknown));\n\n/**\n * `P.unknown` is a wildcard pattern, matching **unknown value**.\n *\n * [Read the documentation for `P.unknown` on GitHub](https://github.com/gvergnaud/ts-pattern#p_-wildcard)\n *\n * @example\n *  match(value)\n *   .with(P.unknown, () => 'will always match')\n */\nexport const unknown: UnknownPattern = chainable(when(isUnknown));\n\n/**\n * `P._` is a wildcard pattern, matching **any value**.\n * It's an alias to `P.any`.\n *\n * [Read the documentation for `P._` on GitHub](https://github.com/gvergnaud/ts-pattern#p_-wildcard)\n *\n * @example\n *  match(value)\n *   .with(P._, () => 'will always match')\n */\nexport const _ = any;\n\n/**\n * `P.string.startsWith(start)` is a pattern, matching **strings** starting with `start`.\n *\n * [Read the documentation for `P.string.startsWith` on GitHub](https://github.com/gvergnaud/ts-pattern#pstringstartsWith)\n *\n * @example\n *  match(value)\n *   .with(P.string.startsWith('A'), () => 'value starts with an A')\n */\n\nconst startsWith = <input, const start extends string>(\n  start: start\n): GuardP<input, `${start}${string}`> =>\n  when((value) => isString(value) && value.startsWith(start));\n\n/**\n * `P.string.endsWith(end)` is a pattern, matching **strings** ending with `end`.\n *\n * [Read the documentation for `P.string.endsWith` on GitHub](https://github.com/gvergnaud/ts-pattern#pstringendsWith)\n *\n * @example\n *  match(value)\n *   .with(P.string.endsWith('!'), () => 'value ends with an !')\n */\nconst endsWith = <input, const end extends string>(\n  end: end\n): GuardP<input, `${string}${end}`> =>\n  when((value) => isString(value) && value.endsWith(end));\n\n/**\n * `P.string.minLength(min)` is a pattern, matching **strings** with at least `min` characters.\n *\n * [Read the documentation for `P.string.minLength` on GitHub](https://github.com/gvergnaud/ts-pattern#pstringminLength)\n *\n * @example\n *  match(value)\n *   .with(P.string.minLength(10), () => 'string with more length >= 10')\n */\nconst minLength = <const min extends number>(min: min) =>\n  when((value) => isString(value) && value.length >= min);\n\n/**\n * `P.string.length(len)` is a pattern, matching **strings** with exactly `len` characters.\n *\n * [Read the documentation for `P.string.length` on GitHub](https://github.com/gvergnaud/ts-pattern#pstringlength)\n *\n * @example\n *  match(value)\n *   .with(P.string.length(10), () => 'strings with length === 10')\n */\nconst length = <const len extends number>(len: len) =>\n  when((value) => isString(value) && value.length === len);\n\n/**\n * `P.string.maxLength(max)` is a pattern, matching **strings** with at most `max` characters.\n *\n * [Read the documentation for `P.string.maxLength` on GitHub](https://github.com/gvergnaud/ts-pattern#pstringmaxLength)\n *\n * @example\n *  match(value)\n *   .with(P.string.maxLength(10), () => 'string with more length <= 10')\n */\nconst maxLength = <const max extends number>(max: max) =>\n  when((value) => isString(value) && value.length <= max);\n\n/**\n * `P.string.includes(substr)` is a pattern, matching **strings** containing `substr`.\n *\n * [Read the documentation for `P.string.includes` on GitHub](https://github.com/gvergnaud/ts-pattern#pstringincludes)\n *\n * @example\n *  match(value)\n *   .with(P.string.includes('http'), () => 'value contains http')\n */\nconst includes = <input, const substr extends string>(\n  substr: substr\n): GuardExcludeP<input, string, never> =>\n  when((value) => isString(value) && value.includes(substr));\n\n/**\n * `P.string.regex(expr)` is a pattern, matching **strings** that `expr` regular expression.\n *\n * [Read the documentation for `P.string.regex` on GitHub](https://github.com/gvergnaud/ts-pattern#pstringregex)\n *\n * @example\n *  match(value)\n *   .with(P.string.regex(/^https?:\\/\\//), () => 'url')\n */\nconst regex = <input, const expr extends string | RegExp>(\n  expr: expr\n): GuardExcludeP<input, string, never> =>\n  when((value) => isString(value) && Boolean(value.match(expr)));\n\nconst stringChainable = <pattern extends Matcher<any, any, any, any, any>>(\n  pattern: pattern\n): StringChainable<pattern> =>\n  Object.assign(chainable(pattern), {\n    startsWith: (str: string) =>\n      stringChainable(intersection(pattern, startsWith(str))),\n    endsWith: (str: string) =>\n      stringChainable(intersection(pattern, endsWith(str))),\n    minLength: (min: number) =>\n      stringChainable(intersection(pattern, minLength(min))),\n    length: (len: number) =>\n      stringChainable(intersection(pattern, length(len))),\n    maxLength: (max: number) =>\n      stringChainable(intersection(pattern, maxLength(max))),\n    includes: (str: string) =>\n      stringChainable(intersection(pattern, includes(str))),\n    regex: (str: string) => stringChainable(intersection(pattern, regex(str))),\n  }) as any;\n\n/**\n * `P.string` is a wildcard pattern, matching any **string**.\n *\n * [Read the documentation for `P.string` on GitHub](https://github.com/gvergnaud/ts-pattern#pstring-wildcard)\n *\n * @example\n *  match(value)\n *   .with(P.string, () => 'will match on strings')\n */\nexport const string: StringPattern = stringChainable(when(isString));\n\n/**\n * `P.number.between(min, max)` matches **numbers** between `min` and `max`,\n * equal to min or equal to max.\n *\n * [Read the documentation for `P.number.between` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumberbetween)\n *\n * @example\n *  match(value)\n *   .with(P.number.between(0, 10), () => '0 <= numbers <= 10')\n */\nconst between = <input, const min extends number, const max extends number>(\n  min: min,\n  max: max\n): GuardExcludeP<input, number, never> =>\n  when((value) => isNumber(value) && min <= value && max >= value);\n\n/**\n * `P.number.lt(max)` matches **numbers** smaller than `max`.\n *\n * [Read the documentation for `P.number.lt` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumberlt)\n *\n * @example\n *  match(value)\n *   .with(P.number.lt(10), () => 'numbers < 10')\n */\nconst lt = <input, const max extends number>(\n  max: max\n): GuardExcludeP<input, number, never> =>\n  when((value) => isNumber(value) && value < max);\n\n/**\n * `P.number.gt(min)` matches **numbers** greater than `min`.\n *\n * [Read the documentation for `P.number.gt` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumbergt)\n *\n * @example\n *  match(value)\n *   .with(P.number.gt(10), () => 'numbers > 10')\n */\nconst gt = <input, const min extends number>(\n  min: min\n): GuardExcludeP<input, number, never> =>\n  when((value) => isNumber(value) && value > min);\n\n/**\n * `P.number.lte(max)` matches **numbers** smaller than or equal to `max`.\n *\n * [Read the documentation for `P.number.lte` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumberlte)\n *\n * @example\n *  match(value)\n *   .with(P.number.lte(10), () => 'numbers <= 10')\n */\nconst lte = <input, const max extends number>(\n  max: max\n): GuardExcludeP<input, number, never> =>\n  when((value) => isNumber(value) && value <= max);\n\n/**\n * `P.number.gte(min)` matches **numbers** greater than or equal to `min`.\n *\n * [Read the documentation for `P.number.gte` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumbergte)\n *\n * @example\n *  match(value)\n *   .with(P.number.gte(10), () => 'numbers >= 10')\n */\nconst gte = <input, const min extends number>(\n  min: min\n): GuardExcludeP<input, number, never> =>\n  when((value) => isNumber(value) && value >= min);\n\n/**\n * `P.number.int()` matches **integer** numbers.\n *\n * [Read the documentation for `P.number.int()` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumberint)\n *\n * @example\n *  match(value)\n *   .with(P.number.int(), () => 'an integer')\n */\nconst int = <input>(): GuardExcludeP<input, number, never> =>\n  when((value) => isNumber(value) && Number.isInteger(value));\n\n/**\n * `P.number.finite` matches **finite numbers**.\n *\n * [Read the documentation for `P.number.finite` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumberfinite)\n *\n * @example\n *  match(value)\n *   .with(P.number.finite, () => 'not Infinity')\n */\nconst finite = <input>(): GuardExcludeP<input, number, never> =>\n  when((value) => isNumber(value) && Number.isFinite(value));\n\n/**\n * `P.number.positive()` matches **positive** numbers.\n *\n * [Read the documentation for `P.number.positive()` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumberpositive)\n *\n * @example\n *  match(value)\n *   .with(P.number.positive(), () => 'number > 0')\n */\nconst positive = <input>(): GuardExcludeP<input, number, never> =>\n  when((value) => isNumber(value) && value > 0);\n\n/**\n * `P.number.negative()` matches **negative** numbers.\n *\n * [Read the documentation for `P.number.negative()` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumbernegative)\n *\n * @example\n *  match(value)\n *   .with(P.number.negative(), () => 'number < 0')\n */\nconst negative = <input>(): GuardExcludeP<input, number, never> =>\n  when((value) => isNumber(value) && value < 0);\n\nconst numberChainable = <pattern extends Matcher<any, any, any, any, any>>(\n  pattern: pattern\n): NumberChainable<pattern> =>\n  Object.assign(chainable(pattern), {\n    between: (min: number, max: number) =>\n      numberChainable(intersection(pattern, between(min, max))),\n    lt: (max: number) => numberChainable(intersection(pattern, lt(max))),\n    gt: (min: number) => numberChainable(intersection(pattern, gt(min))),\n    lte: (max: number) => numberChainable(intersection(pattern, lte(max))),\n    gte: (min: number) => numberChainable(intersection(pattern, gte(min))),\n    int: () => numberChainable(intersection(pattern, int())),\n    finite: () => numberChainable(intersection(pattern, finite())),\n    positive: () => numberChainable(intersection(pattern, positive())),\n    negative: () => numberChainable(intersection(pattern, negative())),\n  }) as any;\n\n/**\n * `P.number` is a wildcard pattern, matching any **number**.\n *\n * [Read the documentation for `P.number` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumber-wildcard)\n *\n * @example\n *  match(value)\n *   .with(P.number, () => 'will match on numbers')\n */\nexport const number: NumberPattern = numberChainable(when(isNumber));\n\n/**\n * `P.bigint.between(min, max)` matches **bigint** between `min` and `max`,\n * equal to min or equal to max.\n *\n * [Read the documentation for `P.bigint.between` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumberbetween)\n *\n * @example\n *  match(value)\n *   .with(P.bigint.between(0, 10), () => '0 <= bigints <= 10')\n */\nconst betweenBigInt = <\n  input,\n  const min extends bigint,\n  const max extends bigint\n>(\n  min: min,\n  max: max\n): GuardExcludeP<input, bigint, never> =>\n  when((value) => isBigInt(value) && min <= value && max >= value);\n\n/**\n * `P.bigint.lt(max)` matches **bigint** smaller than `max`.\n *\n * [Read the documentation for `P.bigint.lt` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumberlt)\n *\n * @example\n *  match(value)\n *   .with(P.bigint.lt(10), () => 'bigints < 10')\n */\nconst ltBigInt = <input, const max extends bigint>(\n  max: max\n): GuardExcludeP<input, bigint, never> =>\n  when((value) => isBigInt(value) && value < max);\n\n/**\n * `P.bigint.gt(min)` matches **bigint** greater than `min`.\n *\n * [Read the documentation for `P.bigint.gt` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumbergt)\n *\n * @example\n *  match(value)\n *   .with(P.bigint.gt(10), () => 'bigints > 10')\n */\nconst gtBigInt = <input, const min extends bigint>(\n  min: min\n): GuardExcludeP<input, bigint, never> =>\n  when((value) => isBigInt(value) && value > min);\n\n/**\n * `P.bigint.lte(max)` matches **bigint** smaller than or equal to `max`.\n *\n * [Read the documentation for `P.bigint.lte` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumberlte)\n *\n * @example\n *  match(value)\n *   .with(P.bigint.lte(10), () => 'bigints <= 10')\n */\nconst lteBigInt = <input, const max extends bigint>(\n  max: max\n): GuardExcludeP<input, bigint, never> =>\n  when((value) => isBigInt(value) && value <= max);\n\n/**\n * `P.bigint.gte(min)` matches **bigint** greater than or equal to `min`.\n *\n * [Read the documentation for `P.bigint.gte` on GitHub](https://github.com/gvergnaud/ts-pattern#pbigintgte)\n *\n * @example\n *  match(value)\n *   .with(P.bigint.gte(10), () => 'bigints >= 10')\n */\nconst gteBigInt = <input, const min extends bigint>(\n  min: min\n): GuardExcludeP<input, bigint, never> =>\n  when((value) => isBigInt(value) && value >= min);\n\n/**\n * `P.bigint.positive()` matches **positive** bigints.\n *\n * [Read the documentation for `P.bigint.positive()` on GitHub](https://github.com/gvergnaud/ts-pattern#pbigintpositive)\n *\n * @example\n *  match(value)\n *   .with(P.bigint.positive(), () => 'bigint > 0')\n */\nconst positiveBigInt = <input>(): GuardExcludeP<input, bigint, never> =>\n  when((value) => isBigInt(value) && value > 0);\n\n/**\n * `P.bigint.negative()` matches **negative** bigints.\n *\n * [Read the documentation for `P.bigint.negative()` on GitHub](https://github.com/gvergnaud/ts-pattern#pbigintnegative)\n *\n * @example\n *  match(value)\n *   .with(P.bigint.negative(), () => 'bigint < 0')\n */\nconst negativeBigInt = <input>(): GuardExcludeP<input, bigint, never> =>\n  when((value) => isBigInt(value) && value < 0);\n\nconst bigintChainable = <pattern extends Matcher<any, any, any, any, any>>(\n  pattern: pattern\n): BigIntChainable<pattern> =>\n  Object.assign(chainable(pattern), {\n    between: (min: bigint, max: bigint) =>\n      bigintChainable(intersection(pattern, betweenBigInt(min, max))),\n    lt: (max: bigint) => bigintChainable(intersection(pattern, ltBigInt(max))),\n    gt: (min: bigint) => bigintChainable(intersection(pattern, gtBigInt(min))),\n    lte: (max: bigint) =>\n      bigintChainable(intersection(pattern, lteBigInt(max))),\n    gte: (min: bigint) =>\n      bigintChainable(intersection(pattern, gteBigInt(min))),\n    positive: () => bigintChainable(intersection(pattern, positiveBigInt())),\n    negative: () => bigintChainable(intersection(pattern, negativeBigInt())),\n  }) as any;\n\n/**\n * `P.bigint` is a wildcard pattern, matching any **bigint**.\n *\n * [Read the documentation for `P.bigint` on GitHub](https://github.com/gvergnaud/ts-pattern#number-wildcard)\n *\n * @example\n *   .with(P.bigint, () => 'will match on bigints')\n */\nexport const bigint: BigIntPattern = bigintChainable(when(isBigInt));\n\n/**\n * `P.boolean` is a wildcard pattern, matching any **boolean**.\n *\n * [Read the documentation for `P.boolean` on GitHub](https://github.com/gvergnaud/ts-pattern#boolean-wildcard)\n *\n * @example\n *   .with(P.boolean, () => 'will match on booleans')\n */\nexport const boolean: BooleanPattern = chainable(when(isBoolean));\n\n/**\n * `P.symbol` is a wildcard pattern, matching any **symbol**.\n *\n * [Read the documentation for `P.symbol` on GitHub](https://github.com/gvergnaud/ts-pattern#symbol-wildcard)\n *\n * @example\n *   .with(P.symbol, () => 'will match on symbols')\n */\nexport const symbol: SymbolPattern = chainable(when(isSymbol));\n\n/**\n * `P.nullish` is a wildcard pattern, matching **null** or **undefined**.\n *\n * [Read the documentation for `P.nullish` on GitHub](https://github.com/gvergnaud/ts-pattern#nullish-wildcard)\n *\n * @example\n *   .with(P.nullish, (x) => `${x} is null or undefined`)\n */\nexport const nullish: NullishPattern = chainable(when(isNullish));\n\n/**\n * `P.nonNullable` is a wildcard pattern, matching everything except **null** or **undefined**.\n *\n * [Read the documentation for `P.nonNullable` on GitHub](https://github.com/gvergnaud/ts-pattern#nonNullable-wildcard)\n *\n * @example\n *   .with(P.nonNullable, (x) => `${x} isn't null nor undefined`)\n */\nexport const nonNullable: NonNullablePattern = chainable(when(isNonNullable));\n\n/**\n * `P.instanceOf(SomeClass)` is a pattern matching instances of a given class.\n *\n * [Read the documentation for `P.instanceOf` on GitHub](https://github.com/gvergnaud/ts-pattern#pinstanceof-patterns)\n *\n *  @example\n *   .with(P.instanceOf(SomeClass), () => 'will match on SomeClass instances')\n */\nexport function instanceOf<T extends AnyConstructor>(\n  classConstructor: T\n): Chainable<GuardP<unknown, InstanceType<T>>> {\n  return chainable(when(isInstanceOf(classConstructor)));\n}\n\n/**\n * `P.shape(somePattern)` lets you call methods like `.optional()`, `.and`, `.or` and `.select()`\n * On structural patterns, like objects and arrays.\n *\n * [Read the documentation for `P.shape` on GitHub](https://github.com/gvergnaud/ts-pattern#pshape-patterns)\n *\n *  @example\n *   .with(\n *     {\n *       state: P.shape({ status: \"success\" }).optional().select()\n *     },\n *     (state) => 'match the success state, or undefined.'\n *   )\n */\nexport function shape<input, const pattern extends Pattern<input>>(\n  pattern: pattern\n): Chainable<GuardP<input, InvertPattern<pattern, input>>>;\nexport function shape(pattern: UnknownValuePattern) {\n  return chainable(when(isMatching(pattern)));\n}\n"
  },
  {
    "path": "src/types/BuildMany.ts",
    "content": "import { Iterator, IsOptionalKeysOf, UpdateAt, ValueOf } from './helpers';\n\n// BuildMany :: DataStructure -> Union<[value, path][]> -> Union<DataStructure>\nexport type BuildMany<data, xs extends readonly any[]> = xs extends any\n  ? BuildOne<data, xs>\n  : never;\n\n// BuildOne :: DataStructure\n// -> [value, path][]\n// -> DataStructure\ntype BuildOne<data, xs extends readonly any[]> = xs extends [\n  [infer value, infer path],\n  ...infer tail\n]\n  ? BuildOne<SetDeep<data, value, path>, tail>\n  : data;\n\n// SetDeep :: a -> b -> PropertyKey[] -> a\nexport type SetDeep<data, value, path> = path extends readonly [\n  infer head,\n  ...infer tail\n]\n  ? data extends readonly any[]\n    ? data extends readonly [any, ...any]\n      ? head extends number\n        ? UpdateAt<data, Iterator<head>, SetDeep<data[head], value, tail>>\n        : never\n      : SetDeep<ValueOf<data>, value, tail>[]\n    : data extends Set<infer a>\n    ? Set<SetDeep<a, value, tail>>\n    : data extends Map<infer k, infer v>\n    ? Map<k, SetDeep<v, value, tail>>\n    : head extends keyof data\n    ? // if we intentionally set undefined on an optional key, we should keep\n      // the optional modifier, otherwise it will exclude the `undefined` type from\n      // our `value` type.\n      [IsOptionalKeysOf<data, head>, tail, undefined] extends [true, [], value]\n      ? { [k in keyof data]: k extends head ? value : data[k] }\n      : {\n          [k in keyof data]-?: k extends head\n            ? SetDeep<data[head], value, tail>\n            : data[k];\n        }\n    : data\n  : value;\n"
  },
  {
    "path": "src/types/DeepExclude.ts",
    "content": "import { DistributeMatchingUnions } from './DistributeUnions';\n\nexport type DeepExclude<a, b> = Exclude<DistributeMatchingUnions<a, b>, b>;\n"
  },
  {
    "path": "src/types/DistributeUnions.ts",
    "content": "import { BuildMany } from './BuildMany';\nimport type {\n  IsAny,\n  Values,\n  Flatten,\n  IsUnion,\n  IsPlainObject,\n  Length,\n  UnionToTuple,\n  IsReadonlyArray,\n  ValueOf,\n  MaybeAddReadonly,\n  IsStrictArray,\n} from './helpers';\nimport { IsMatching } from './IsMatching';\n\n/**\n * DistributeMatchingUnions takes two arguments:\n * - a data structure of type `a` containing unions\n * - a pattern `p`, matching this data structure\n * and turns it into a union of all possible\n * combination of each unions contained in `a` that matches `p`.\n *\n * It does this in 3 main steps:\n *  - 1. Find all unions contained in the data structure, that matches `p`\n *    with `FindUnions<a, p>`. It returns a tree of [union, path] pairs.\n *  - 2. this tree is passed to the `Distribute` type level function,\n *    Which turns it into a union of list of `[singleValue, path]` pairs.\n *    Each list correspond to one of the possible combination of the unions\n *    found in `a`.\n *  - 3. build a data structure with the same shape as `a` for each combination\n *    and return the union of these data structures.\n *\n * @example\n * type t1 = DistributeMatchingUnions<['a' | 'b', 1 | 2], ['a', 1]>;\n * // => ['a', 1] | ['a', 2] | ['b', 1] | ['b', 2]\n *\n * type t2 = DistributeMatchingUnions<['a' | 'b', 1 | 2], ['a', unknown]>;\n * // => ['a', 1 | 2] | ['b', 1 | 2]\n */\nexport type DistributeMatchingUnions<a, p> = IsAny<a> extends true\n  ? any\n  : BuildMany<a, Distribute<FindUnionsMany<a, p>>>;\n\n// FindUnionsMany :: a -> Union<a> -> PropertyKey[] -> UnionConfig[]\nexport type FindUnionsMany<\n  a,\n  p,\n  path extends PropertyKey[] = []\n> = UnionToTuple<\n  (\n    p extends any\n      ? IsMatching<a, p> extends true\n        ? FindUnions<a, p, path>\n        : []\n      : never\n  ) extends readonly (infer T)[]\n    ? T\n    : never\n>;\n\n/**\n * The reason we don't look further down the tree with lists,\n * Set and Maps is that they can be heterogeneous,\n * so matching on a A[] for a in input of (A|B)[]\n * doesn't rule anything out. You can still have\n * a (A|B)[] afterward. The same logic goes for Set and Maps.\n *\n * Kinds are types of types.\n *\n * kind UnionConfig = {\n *  cases: Union<{\n *    value: b,\n *    subUnions: UnionConfig[]\n *  }>,\n *  path: string[]\n * }\n * FindUnions :: Pattern a p => a -> p -> UnionConfig[]\n */\nexport type FindUnions<\n  a,\n  p,\n  path extends PropertyKey[] = []\n> = unknown extends p\n  ? []\n  : IsAny<p> extends true\n  ? [] // Don't try to find unions after 5 levels\n  : Length<path> extends 5\n  ? []\n  : IsUnion<a> extends true\n  ? [\n      {\n        cases: a extends any\n          ? {\n              value: a;\n              subUnions: FindUnionsMany<a, p, path>;\n            }\n          : never;\n        path: path;\n      }\n    ]\n  : [a, p] extends [readonly any[], readonly any[]]\n  ? [a, p] extends [\n      readonly [infer a1, infer a2, infer a3, infer a4, infer a5],\n      readonly [infer p1, infer p2, infer p3, infer p4, infer p5]\n    ]\n    ? [\n        ...FindUnions<a1, p1, [...path, 0]>,\n        ...FindUnions<a2, p2, [...path, 1]>,\n        ...FindUnions<a3, p3, [...path, 2]>,\n        ...FindUnions<a4, p4, [...path, 3]>,\n        ...FindUnions<a5, p5, [...path, 4]>\n      ]\n    : [a, p] extends [\n        readonly [infer a1, infer a2, infer a3, infer a4],\n        readonly [infer p1, infer p2, infer p3, infer p4]\n      ]\n    ? [\n        ...FindUnions<a1, p1, [...path, 0]>,\n        ...FindUnions<a2, p2, [...path, 1]>,\n        ...FindUnions<a3, p3, [...path, 2]>,\n        ...FindUnions<a4, p4, [...path, 3]>\n      ]\n    : [a, p] extends [\n        readonly [infer a1, infer a2, infer a3],\n        readonly [infer p1, infer p2, infer p3]\n      ]\n    ? [\n        ...FindUnions<a1, p1, [...path, 0]>,\n        ...FindUnions<a2, p2, [...path, 1]>,\n        ...FindUnions<a3, p3, [...path, 2]>\n      ]\n    : [a, p] extends [\n        readonly [infer a1, infer a2],\n        readonly [infer p1, infer p2]\n      ]\n    ? [...FindUnions<a1, p1, [...path, 0]>, ...FindUnions<a2, p2, [...path, 1]>]\n    : [a, p] extends [readonly [infer a1], readonly [infer p1]]\n    ? FindUnions<a1, p1, [...path, 0]>\n    : /**\n     * Special case when matching with a variadic tuple on a regular array.\n     * in this case we turn the input array `A[]` into `[] | [A, ...A[]]`\n     * to remove one of these cases during DeepExclude.\n     */\n    p extends readonly [] | readonly [any, ...any] | readonly [...any, any]\n    ? IsStrictArray<Extract<a, readonly any[]>> extends false\n      ? []\n      : [\n          ArrayToVariadicUnion<a, p> extends infer aUnion\n            ? {\n                cases: aUnion extends any\n                  ? {\n                      value: aUnion;\n                      subUnions: [];\n                    }\n                  : never;\n                path: path;\n              }\n            : never\n        ]\n    : []\n  : a extends Set<any>\n  ? []\n  : a extends Map<any, any>\n  ? []\n  : [IsPlainObject<a>, IsPlainObject<p>] extends [true, true]\n  ? Flatten<\n      Values<{\n        [k in keyof a & keyof p]: FindUnions<a[k], p[k], [...path, k]>;\n      }>\n    >\n  : [];\n\nexport type ArrayToVariadicUnion<input, excluded> = MaybeAddReadonly<\n  | (input extends readonly [any, ...any] | readonly [...any, any] ? never : [])\n  | (excluded extends readonly [...any, any]\n      ? [...Extract<input, readonly any[]>, ValueOf<input>]\n      : [ValueOf<input>, ...Extract<input, readonly any[]>]),\n  IsReadonlyArray<input>\n>;\n\n// Distribute :: UnionConfig[] -> Union<[a, path][]>\nexport type Distribute<unions extends readonly any[]> =\n  unions extends readonly [\n    { cases: infer cases; path: infer path },\n    ...infer tail\n  ]\n    ? cases extends { value: infer value; subUnions: infer subUnions }\n      ? [\n          [value, path],\n          ...Distribute<Extract<subUnions, readonly any[]>>,\n          ...Distribute<tail>\n        ]\n      : never\n    : [];\n"
  },
  {
    "path": "src/types/ExtractPreciseValue.ts",
    "content": "import type { Override } from './Pattern';\nimport type {\n  BuiltInObjects,\n  Compute,\n  Contains,\n  IsPlainObject,\n  IsReadonlyArray,\n  LeastUpperBound,\n  MaybeAddReadonly,\n  ValueOf,\n} from './helpers';\n\nexport type ExtractPreciseValue<a, b> = b extends Override<infer b1>\n  ? b1\n  : unknown extends b\n  ? a\n  : // inlining IsAny for perf\n  0 extends 1 & b\n  ? a\n  : // inlining IsAny for perf\n  0 extends 1 & a\n  ? b\n  : b extends readonly any[]\n  ? ExtractPreciseArrayValue<a, b, IsReadonlyArray<a>>\n  : b extends Map<infer bk, infer bv>\n  ? a extends Map<infer ak, infer av>\n    ? Map<ExtractPreciseValue<ak, bk>, ExtractPreciseValue<av, bv>>\n    : LeastUpperBound<a, b>\n  : b extends Set<infer bv>\n  ? a extends Set<infer av>\n    ? Set<ExtractPreciseValue<av, bv>>\n    : LeastUpperBound<a, b>\n  : // We add `Error` to the excludeUnion because\n  // We want to consider them like primitive values in this context.\n  IsPlainObject<b, BuiltInObjects | Error> extends true\n  ? a extends object\n    ? a extends b\n      ? a\n      : b extends a\n      ? Contains<b, never> extends true\n        ? never\n        : // An empty object `{}` in a pattern means\n        // that this key must be non-nullable.\n        // If we find a key in `b` that doesn't exist in `a`\n        // and that contains `{}`, then the pattern does not match.\n        Contains<Omit<b, keyof a>, {}> extends true\n        ? never\n        : // If values have no keys in common, return `b`\n        [Exclude<keyof a, keyof b>] extends [never]\n        ? b\n        : // Otherwise return `b` with keys of `a`\n          // that do not exist on `b`.\n          // It can only be optional properties,\n          // otherwise `b extends a` wouldn't\n          // not have passed.\n          Compute<b & Omit<a, keyof b>>\n      : [keyof a & keyof b] extends [never]\n      ? never\n      : Compute<\n          // Keep other properties of `a`\n          {\n            // `in keyof a as ...` preserves property modifiers,\n            // unlike `in keyof Exclude<keyof a, keyof b>`.\n            [k in keyof a as k extends keyof b ? never : k]: a[k];\n          } & {\n            // use `b` to extract precise values on `a`.\n            // This has the effect of preserving the optional\n            // property modifier (?:) of b in the output type.\n            [k in keyof b]: k extends keyof a\n              ? ExtractPreciseValue<a[k], b[k]>\n              : b[k];\n          }\n        > extends infer result\n      ? Contains<Pick<result, keyof result & keyof b>, never> extends true\n        ? never\n        : result\n      : never\n    : LeastUpperBound<a, b>\n  : LeastUpperBound<a, b>;\n\ntype ExtractPreciseArrayValue<\n  a,\n  b,\n  isReadonly extends boolean,\n  startOutput extends any[] = [],\n  endOutput extends any[] = []\n> = a extends readonly (infer aItem)[]\n  ? b extends readonly []\n    ? MaybeAddReadonly<[...startOutput, ...endOutput], isReadonly>\n    : b extends readonly [infer b1, ...infer bRest]\n    ? a extends readonly [infer a1, ...infer aRest]\n      ? ExtractPreciseValue<a1, b1> extends infer currentValue\n        ? [currentValue] extends [never]\n          ? never\n          : ExtractPreciseArrayValue<\n              aRest,\n              bRest,\n              isReadonly,\n              [...startOutput, currentValue],\n              endOutput\n            >\n        : never\n      : ExtractPreciseValue<aItem, b1> extends infer currentValue\n      ? [currentValue] extends [never]\n        ? never\n        : ExtractPreciseArrayValue<\n            aItem[],\n            bRest,\n            isReadonly,\n            [...startOutput, currentValue],\n            endOutput\n          >\n      : never\n    : b extends readonly [...infer bInit, infer b1]\n    ? a extends readonly [...infer aInit, infer a1]\n      ? ExtractPreciseValue<a1, b1> extends infer currentValue\n        ? [currentValue] extends [never]\n          ? never\n          : ExtractPreciseArrayValue<\n              aInit,\n              bInit,\n              isReadonly,\n              startOutput,\n              [...endOutput, currentValue]\n            >\n        : never\n      : ExtractPreciseValue<aItem, b1> extends infer currentValue\n      ? [currentValue] extends [never]\n        ? never\n        : ExtractPreciseArrayValue<\n            aItem[],\n            bInit,\n            isReadonly,\n            startOutput,\n            [...endOutput, currentValue]\n          >\n      : never\n    : ExtractPreciseValue<aItem, ValueOf<b>> extends infer currentValue\n    ? [currentValue] extends [never]\n      ? never\n      : MaybeAddReadonly<\n          [...startOutput, ...currentValue[], ...endOutput],\n          isReadonly\n        >\n    : never\n  : LeastUpperBound<a, b>;\n"
  },
  {
    "path": "src/types/FindSelected.ts",
    "content": "import type * as symbols from '../internals/symbols';\nimport type { AnyMatcher, Matcher, Pattern } from './Pattern';\nimport type {\n  Equal,\n  Primitives,\n  ValueOf,\n  MergeUnion,\n  IsUnion,\n} from './helpers';\n\ntype SelectionsRecord = Record<string, [unknown, unknown[]]>;\n\nexport type None = {\n  type: 'none';\n};\nexport type Some<key extends string> = {\n  type: 'some';\n  key: key;\n};\n\nexport type SelectionType = None | Some<string>;\n\n// SelectionsRecord -> SelectionsRecord\ntype MapOptional<selections> = {\n  [k in keyof selections]: selections[k] extends [infer v, infer subpath]\n    ? [v | undefined, subpath]\n    : never;\n};\n\n// SelectionsRecord -> SelectionsRecord\ntype MapList<selections> = {\n  [k in keyof selections]: selections[k] extends [infer v, infer subpath]\n    ? [v[], subpath]\n    : never;\n};\n\n// input -> pattern[] -> (string | number)[] -> Union SelectionRecord\ntype ReduceFindSelectionUnion<\n  i,\n  ps extends readonly any[],\n  output = never\n> = ps extends readonly [infer head, ...infer tail]\n  ? ReduceFindSelectionUnion<i, tail, output | FindSelectionUnion<i, head>>\n  : output;\n\n// input -> pattern -> (string | number)[] -> Union SelectionRecord\ntype FindSelectionUnionInArray<\n  i,\n  p,\n  path extends any[] = [],\n  output = never\n> = i extends readonly (infer iItem)[]\n  ? p extends readonly []\n    ? output\n    : p extends readonly [infer p1, ...infer pRest]\n    ? i extends readonly [infer i1, ...infer iRest]\n      ? FindSelectionUnionInArray<\n          iRest,\n          pRest,\n          [...path, p['length']],\n          output | FindSelectionUnion<i1, p1, [...path, p['length']]>\n        >\n      : FindSelectionUnionInArray<\n          iItem[],\n          pRest,\n          [...path, p['length']],\n          output | FindSelectionUnion<iItem, p1, [...path, p['length']]>\n        >\n    : p extends readonly [...infer pInit, infer p1]\n    ? i extends readonly [...infer iInit, infer i1]\n      ? FindSelectionUnionInArray<\n          iInit,\n          pInit,\n          [...path, p['length']],\n          output | FindSelectionUnion<i1, p1, [...path, p['length']]>\n        >\n      : FindSelectionUnionInArray<\n          iItem[],\n          pInit,\n          [...path, p['length']],\n          output | FindSelectionUnion<iItem, p1, [...path, p['length']]>\n        >\n    : // If P is a matcher, in this case, it's likely an array matcher\n    p extends readonly [...(readonly (infer pRest & AnyMatcher)[])]\n    ? output | FindSelectionUnion<i, pRest, [...path, p['length']]>\n    :\n        | output\n        | FindSelectionUnion<\n            iItem,\n            ValueOf<p>,\n            [...path, Extract<p, readonly any[]>['length']]\n          >\n  : output;\n\n// input -> pattern -> (string | number)[] -> SelectionsRecord\nexport type FindSelectionUnion<\n  i,\n  p,\n  // path just serves as an id, to identify different anonymous patterns which have the same type\n  path extends any[] = []\n  // inlining IsAny for perf\n> = 0 extends 1 & i\n  ? never\n  : // inlining IsAny for perf\n  0 extends 1 & p\n  ? never\n  : p extends Primitives\n  ? never\n  : p extends Matcher<any, infer pattern, infer matcherType, infer sel>\n  ? {\n      select: sel extends Some<infer k>\n        ? { [kk in k]: [i, path] } | FindSelectionUnion<i, pattern, path>\n        : never;\n      // selection of arrays, records, maps, and sets are arrays,\n      // because the selection function is being mapped on their values\n      array: i extends readonly (infer iItem)[]\n        ? MapList<FindSelectionUnion<iItem, pattern>>\n        : never;\n      record: [i, pattern] extends [\n        Record<infer k, infer v>,\n        [infer pkey, infer pvalue]\n      ]\n        ?\n            | MapList<FindSelectionUnion<k, pkey, path>>\n            | MapList<FindSelectionUnion<v, pvalue, path>>\n        : never;\n      map: [i, pattern] extends [\n        Map<infer k, infer v>,\n        [infer pkey, infer pvalue]\n      ]\n        ?\n            | MapList<FindSelectionUnion<k, pkey, path>>\n            | MapList<FindSelectionUnion<v, pvalue, path>>\n        : never;\n      set: i extends Set<infer v>\n        ? MapList<FindSelectionUnion<v, pattern, path>>\n        : never;\n      optional: MapOptional<FindSelectionUnion<i, pattern>>;\n      or: MapOptional<\n        ReduceFindSelectionUnion<i, Extract<pattern, readonly any[]>>\n      >;\n      and: ReduceFindSelectionUnion<i, Extract<pattern, readonly any[]>>;\n      not: never;\n      default: sel extends Some<infer k> ? { [kk in k]: [i, path] } : never;\n      custom: never;\n    }[matcherType]\n  : p extends readonly any[]\n  ? FindSelectionUnionInArray<i, p>\n  : p extends {}\n  ? i extends {}\n    ? {\n        [k in keyof p]: k extends keyof i\n          ? FindSelectionUnion<i[k], p[k], [...path, k]>\n          : never;\n      }[keyof p]\n    : never\n  : never;\n\nexport type SeveralAnonymousSelectError<\n  a = 'You can only use a single anonymous selection (with `select()`) in your pattern. If you need to select multiple values, give them names with `select(<name>)` instead'\n> = {\n  __error: never;\n} & a;\n\nexport type MixedNamedAndAnonymousSelectError<\n  a = 'Mixing named selections (`select(\"name\")`) and anonymous selections (`select()`) is forbiden. Please, only use named selections.'\n> = {\n  __error: never;\n} & a;\n\n//                       Multiple selections   Single selection\n//                                 👇               👇\n// SelectionsRecord -> Record<string, unknown> | unknown | Error\nexport type SelectionToArgs<selections extends SelectionsRecord> =\n  symbols.anonymousSelectKey extends keyof selections\n    ? // if there are several different paths for anonymous selections\n      // it means that P.select() has been used more than once.\n      IsUnion<selections[symbols.anonymousSelectKey][1]> extends true\n      ? SeveralAnonymousSelectError\n      : keyof selections extends symbols.anonymousSelectKey\n      ? selections[symbols.anonymousSelectKey][0]\n      : MixedNamedAndAnonymousSelectError\n    : { [k in keyof selections]: selections[k][0] };\n\nexport type Selections<i, p> = FindSelectionUnion<i, p> extends infer u\n  ? [u] extends [never]\n    ? i\n    : SelectionToArgs<Extract<MergeUnion<u>, SelectionsRecord>>\n  : i;\n\nexport type FindSelected<i, p> =\n  // This happens if the provided pattern didn't extend Pattern<i>,\n  // Because the type checker falls back on the general `Pattern<i>` type\n  // in this case.\n  Equal<p, Pattern<i>> extends true ? i : Selections<i, p>;\n"
  },
  {
    "path": "src/types/InvertPattern.ts",
    "content": "import { DeepExclude } from './DeepExclude';\nimport {\n  IsPlainObject,\n  Primitives,\n  IsLiteral,\n  ValueOf,\n  Compute,\n  Equal,\n  Extends,\n  Not,\n  All,\n  NonLiteralPrimitive,\n  MaybeAddReadonly,\n  IsReadonlyArray,\n  MapKey,\n  MapValue,\n  SetValue,\n  ExtractPlainObject,\n  GetKey,\n  Call,\n  Fn,\n  ReadonlyArrayValue,\n  WithDefault,\n  RecordKey,\n  RecordValue,\n} from './helpers';\nimport type { Matcher, Pattern, Override, AnyMatcher } from './Pattern';\n\ntype OptionalKeys<p> = ValueOf<{\n  [k in keyof p]: 0 extends 1 & p[k] // inlining IsAny for perf\n    ? never\n    : p[k] extends Matcher<any, any, infer matcherType>\n    ? matcherType extends 'optional'\n      ? k\n      : never\n    : never;\n}>;\n\ntype ReduceUnion<\n  tuple extends readonly any[],\n  i,\n  output = never\n> = tuple extends readonly [infer p, ...infer tail]\n  ? ReduceUnion<tail, i, output | InvertPatternInternal<p, i>>\n  : output;\n\ntype ReduceIntersection<\n  tuple extends readonly any[],\n  i,\n  output = unknown\n> = tuple extends readonly [infer p, ...infer tail]\n  ? ReduceIntersection<tail, i, output & InvertPatternInternal<p, i>>\n  : output;\n\ntype InvertArrayPattern<\n  p,\n  i,\n  startOutput extends any[] = [],\n  endOutput extends any[] = []\n> = i extends readonly (infer ii)[]\n  ? p extends readonly []\n    ? [...startOutput, ...endOutput]\n    : p extends readonly [infer p1, ...infer pRest]\n    ? i extends readonly [infer i1, ...infer iRest]\n      ? InvertArrayPattern<\n          pRest,\n          iRest,\n          [...startOutput, InvertPatternInternal<p1, i1>],\n          endOutput\n        >\n      : InvertArrayPattern<\n          pRest,\n          ii[],\n          [...startOutput, InvertPatternInternal<p1, ii>],\n          endOutput\n        >\n    : p extends readonly [...infer pInit, infer p1]\n    ? i extends readonly [...infer iInit, infer i1]\n      ? InvertArrayPattern<\n          pInit,\n          iInit,\n          startOutput,\n          [...endOutput, InvertPatternInternal<p1, i1>]\n        >\n      : InvertArrayPattern<\n          pInit,\n          ii[],\n          startOutput,\n          [...endOutput, InvertPatternInternal<p1, ii>]\n        >\n    : // If P is a matcher, in this case, it's likely an array matcher\n    p extends readonly [...(readonly (infer pRest & AnyMatcher)[])]\n    ? [\n        ...startOutput,\n        ...Extract<InvertPatternInternal<pRest, i>, readonly any[]>,\n        ...endOutput\n      ]\n    : [...startOutput, ...InvertPatternInternal<ValueOf<p>, ii>[], ...endOutput]\n  : never;\n\n/**\n * ### InvertPatternInternal\n * Since patterns have special wildcard values, we need a way\n * to transform a pattern into the type of value it represents\n */\nexport type InvertPattern<p, input> = Equal<Pattern<input>, p> extends true\n  ? never\n  : InvertPatternInternal<p, input>;\n\ntype InvertPatternInternal<p, input> = 0 extends 1 & p\n  ? never\n  : p extends Matcher<\n      infer _input,\n      infer subpattern,\n      infer matcherType,\n      any,\n      infer narrowedOrFn\n    >\n  ? {\n      not: DeepExclude<input, InvertPatternInternal<subpattern, input>>;\n      select: InvertPatternInternal<subpattern, input>;\n      array: InvertPatternInternal<subpattern, ReadonlyArrayValue<input>>[];\n      record: subpattern extends [infer pk, infer pv]\n        ? Record<\n            Extract<InvertPatternInternal<pk, RecordKey<input>>, PropertyKey>,\n            InvertPatternInternal<pv, RecordValue<input>>\n          >\n        : never;\n      map: subpattern extends [infer pk, infer pv]\n        ? Map<\n            InvertPatternInternal<pk, MapKey<Extract<input, Map<any, any>>>>,\n            InvertPatternInternal<pv, MapValue<Extract<input, Map<any, any>>>>\n          >\n        : never;\n      set: Set<\n        InvertPatternInternal<subpattern, SetValue<Extract<input, Set<any>>>>\n      >;\n      optional:\n        | InvertPatternInternal<subpattern, Exclude<input, undefined>>\n        | undefined;\n      and: ReduceIntersection<Extract<subpattern, readonly any[]>, input>;\n      or: ReduceUnion<Extract<subpattern, readonly any[]>, input>;\n      default: [subpattern] extends [never] ? input : subpattern;\n      custom: Override<\n        narrowedOrFn extends Fn ? Call<narrowedOrFn, input> : narrowedOrFn\n      >;\n    }[matcherType]\n  : p extends Primitives\n  ? p\n  : p extends readonly any[]\n  ? InvertArrayPattern<\n      p,\n      WithDefault<Extract<input, readonly any[]>, unknown[]>\n    >\n  : IsPlainObject<p> extends true\n  ? OptionalKeys<p> extends infer optKeys\n    ? [optKeys] extends [never]\n      ? {\n          [k in Exclude<keyof p, optKeys>]: InvertPatternInternal<\n            p[k],\n            WithDefault<GetKey<ExtractPlainObject<input>, k>, unknown>\n          >;\n        }\n      : Compute<\n          {\n            [k in Exclude<keyof p, optKeys>]: InvertPatternInternal<\n              p[k],\n              WithDefault<GetKey<ExtractPlainObject<input>, k>, unknown>\n            >;\n          } & {\n            [k in Extract<optKeys, keyof p>]?: InvertPatternInternal<\n              p[k],\n              WithDefault<GetKey<ExtractPlainObject<input>, k>, unknown>\n            >;\n          }\n        >\n    : never\n  : p;\n\nexport type ReduceIntersectionForExclude<\n  tuple extends readonly any[],\n  i,\n  output = unknown\n> = tuple extends readonly [infer p, ...infer tail]\n  ? ReduceIntersectionForExclude<\n      tail,\n      i,\n      output & InvertPatternForExcludeInternal<p, i, unknown>\n    >\n  : output;\n\nexport type ReduceUnionForExclude<\n  tuple extends readonly any[],\n  i,\n  output = never\n> = tuple extends readonly [infer p, ...infer tail]\n  ? ReduceUnionForExclude<\n      tail,\n      i,\n      output | InvertPatternForExcludeInternal<p, i, never>\n    >\n  : output;\n\ntype ExcludeIfExists<a, b> =\n  // If b is of type never, it probably means that P.not\n  // was called with a `P.when` that wasn't a type guard function.\n  // in this case we do not exclude\n  [b] extends [never]\n    ? never\n    : // If a is unknown, we can't exclude\n    // (Unless negative types are added in the future)\n    unknown extends a\n    ? never\n    : All<\n        [\n          // if `a` is one of the non-literal primitive\n          Extends<a, NonLiteralPrimitive>,\n          Not<IsLiteral<a>>,\n          // and b is a literal\n          IsLiteral<b>\n        ]\n      > extends true\n    ? // we shouldn't exclude because this will result in\n      // excluding the whole primitive type even though only\n      // one value has been handled by this pattern.\n      // In other words `P.not(10)` on a `number` input shouldn't\n      // exclude `number`.\n      never\n    : DeepExclude<a, b>;\n\ntype InvertArrayPatternForExclude<\n  p,\n  i,\n  empty,\n  isReadonly extends boolean,\n  startOutput extends any[] = [],\n  endOutput extends any[] = []\n> = i extends readonly (infer ii)[]\n  ? p extends readonly []\n    ? MaybeAddReadonly<[...startOutput, ...endOutput], isReadonly>\n    : p extends readonly [infer p1, ...infer pRest]\n    ? i extends readonly [infer i1, ...infer iRest]\n      ? InvertArrayPatternForExclude<\n          pRest,\n          iRest,\n          empty,\n          isReadonly,\n          [...startOutput, InvertPatternForExcludeInternal<p1, i1, empty>],\n          endOutput\n        >\n      : InvertArrayPatternForExclude<\n          pRest,\n          ii[],\n          empty,\n          isReadonly,\n          [...startOutput, InvertPatternForExcludeInternal<p1, ii, empty>],\n          endOutput\n        >\n    : p extends readonly [...infer pInit, infer p1]\n    ? i extends readonly [...infer iInit, infer i1]\n      ? InvertArrayPatternForExclude<\n          pInit,\n          iInit,\n          empty,\n          isReadonly,\n          startOutput,\n          [...endOutput, InvertPatternForExcludeInternal<p1, i1, empty>]\n        >\n      : InvertArrayPatternForExclude<\n          pInit,\n          ii[],\n          empty,\n          isReadonly,\n          startOutput,\n          [...endOutput, InvertPatternForExcludeInternal<p1, ii, empty>]\n        >\n    : // If P is a matcher, in this case, it's likely an array matcher\n    p extends readonly [...(readonly (infer pRest & AnyMatcher)[])]\n    ? MaybeAddReadonly<\n        [\n          ...startOutput,\n          ...Extract<\n            InvertPatternForExcludeInternal<pRest, i, empty>,\n            readonly any[]\n          >,\n          ...endOutput\n        ],\n        isReadonly\n      >\n    : MaybeAddReadonly<\n        [\n          ...startOutput,\n          ...InvertPatternForExcludeInternal<ValueOf<p>, ii, empty>[],\n          ...endOutput\n        ],\n        isReadonly\n      >\n  : empty;\n\n/**\n * ### InvertPatternForExclude\n */\nexport type InvertPatternForExclude<p, i> = Equal<Pattern<i>, p> extends true\n  ? never\n  : InvertPatternForExcludeInternal<p, i>;\n\ntype InvertPatternForExcludeInternal<p, i, empty = never> =\n  // We need to prevent distribution because the boolean\n  // type is a union of literal as well as a Primitive type\n  // and it will end up being a false positif if we distribute it.\n  unknown extends p\n    ? i\n    : [p] extends [Primitives]\n    ? IsLiteral<p> extends true\n      ? p\n      : IsLiteral<i> extends true\n      ? p\n      : empty\n    : p extends Matcher<\n        infer matchableInput,\n        infer subpattern,\n        infer matcherType,\n        any,\n        infer excluded\n      >\n    ? {\n        select: InvertPatternForExcludeInternal<subpattern, i, empty>;\n        array: i extends readonly (infer ii)[]\n          ? MaybeAddReadonly<\n              InvertPatternForExcludeInternal<subpattern, ii, empty>[],\n              IsReadonlyArray<i>\n            >\n          : empty;\n        record: subpattern extends [infer pk, infer pv]\n          ? Record<\n              Extract<\n                InvertPatternForExcludeInternal<pk, RecordKey<i>, empty>,\n                PropertyKey\n              >,\n              InvertPatternForExcludeInternal<pv, RecordValue<i>, empty>\n            >\n          : empty;\n        map: subpattern extends [infer pk, infer pv]\n          ? i extends Map<infer ik, infer iv>\n            ? Map<\n                InvertPatternForExcludeInternal<pk, ik, empty>,\n                InvertPatternForExcludeInternal<pv, iv, empty>\n              >\n            : empty\n          : empty;\n        set: i extends Set<infer iv>\n          ? Set<InvertPatternForExcludeInternal<subpattern, iv, empty>>\n          : empty;\n        optional:\n          | InvertPatternForExcludeInternal<subpattern, i, empty>\n          | undefined;\n        and: ReduceIntersectionForExclude<\n          Extract<subpattern, readonly any[]>,\n          i\n        >;\n        or: ReduceUnionForExclude<Extract<subpattern, readonly any[]>, i>;\n        not: ExcludeIfExists<\n          // we use matchableInput if possible because it represent the\n          // union of all possible value, but i is only one of these values.\n          unknown extends matchableInput ? i : matchableInput,\n          InvertPatternForExcludeInternal<subpattern, i>\n        >;\n        default: excluded;\n        custom: excluded extends infer narrowedOrFn extends Fn\n          ? Call<narrowedOrFn, i>\n          : excluded;\n      }[matcherType]\n    : p extends readonly any[]\n    ? Extract<i, readonly any[]> extends infer arrayInput\n      ? InvertArrayPatternForExclude<\n          p,\n          arrayInput,\n          empty,\n          IsReadonlyArray<arrayInput>\n        >\n      : never\n    : IsPlainObject<p> extends true\n    ? Equal<{}, p> extends true\n      ? {}\n      : i extends object\n      ? [keyof p & keyof i] extends [never]\n        ? empty\n        : OptionalKeys<p> extends infer optKeys\n        ? [optKeys] extends [never]\n          ? {\n              readonly [k in keyof p]: k extends keyof i\n                ? InvertPatternForExcludeInternal<p[k], i[k], empty>\n                : InvertPatternInternal<p[k], unknown>;\n            }\n          : Compute<\n              {\n                readonly [k in Exclude<keyof p, optKeys>]: k extends keyof i\n                  ? InvertPatternForExcludeInternal<p[k], i[k], empty>\n                  : InvertPatternInternal<p[k], unknown>;\n              } & {\n                readonly [k in Extract<optKeys, keyof p>]?: k extends keyof i\n                  ? InvertPatternForExcludeInternal<p[k], i[k], empty>\n                  : InvertPatternInternal<p[k], unknown>;\n              }\n            >\n        : empty\n      : empty\n    : empty;\n"
  },
  {
    "path": "src/types/IsMatching.ts",
    "content": "import {\n  Primitives,\n  IsPlainObject,\n  IsUnion,\n  ValueOf,\n  Length,\n  IsLiteral,\n  All,\n  Equal,\n} from './helpers';\n\ntype IsMatchingTuple<a extends readonly any[], b extends readonly any[]> = [\n  a,\n  b\n] extends [readonly [], readonly []]\n  ? true\n  : [a, b] extends [\n      readonly [infer a1, ...infer aRest],\n      readonly [infer b1, ...infer bRest]\n    ]\n  ? IsMatching<a1, b1> extends true\n    ? IsMatchingTuple<aRest, bRest>\n    : false\n  : false;\n\ntype IsMatchingArray<\n  a extends readonly any[],\n  b extends readonly any[]\n> = b extends readonly []\n  ? true // if b is an empty array and a is an array, the pattern matches.\n  : b extends readonly [infer b1, ...infer bRest]\n  ? a extends readonly [infer a1, ...infer aRest]\n    ? IsMatching<a1, b1> extends true\n      ? IsMatchingArray<aRest, bRest>\n      : false\n    : // if a is shorter than b, doesn't match\n    // example: a is [], b is [any, ...any[]]\n    a extends readonly []\n    ? false\n    : IsMatching<ValueOf<a>, b1> extends true\n    ? IsMatchingArray<a, bRest>\n    : false\n  : b extends readonly [...infer bInit, infer b1]\n  ? a extends readonly [...infer aInit, infer a1]\n    ? IsMatching<a1, b1> extends true\n      ? IsMatchingArray<aInit, bInit>\n      : false\n    : // if a is shorter than b, doesn't match\n    // example: a is [], b is [any, ...any[]]\n    a extends readonly []\n    ? false\n    : IsMatching<ValueOf<a>, b1> extends true\n    ? IsMatchingArray<a, bInit>\n    : false\n  : IsMatching<ValueOf<a>, ValueOf<b>>;\n\nexport type IsMatching<a, b> = true extends IsUnion<a> | IsUnion<b>\n  ? true extends (\n      b extends any ? (a extends any ? IsMatching<a, b> : never) : never\n    )\n    ? true\n    : false\n  : // Special case for unknown, because this is the type\n  // of the inverted `_` wildcard pattern, which should\n  // match everything.\n  unknown extends b\n  ? true\n  : // Special case for `{}`, because this is the type\n  // of the inverted `P.nonNullable` wildcard pattern,\n  // which should match all objects.\n  {} extends b\n  ? true\n  : b extends Primitives\n  ? // if the pattern is a primitive, we want to check if there is\n    // an overlap between a and b!\n    a extends b\n    ? true\n    : b extends a\n    ? true\n    : false\n  : Equal<a, b> extends true\n  ? true\n  : b extends readonly any[]\n  ? a extends readonly any[]\n    ? // both tuples\n      All<[IsLiteral<Length<a>>, IsLiteral<Length<b>>]> extends true\n      ? // lengths are different\n        Equal<Length<a>, Length<b>> extends false\n        ? false\n        : IsMatchingTuple<a, b>\n      : IsMatchingArray<a, b>\n    : false\n  : IsPlainObject<b> extends true\n  ? true extends ( // `true extends union` means \"if some cases of the a union are matching\"\n      a extends any // loop over the `a` union\n        ? [keyof b & keyof a] extends [never] // if no common keys\n          ? false\n          : /**\n           * Intentionally not using ValueOf, to avoid reaching the\n           * 'type instanciation is too deep error'.\n           */\n          { [k in keyof b & keyof a]: IsMatching<a[k], b[k]> }[keyof b &\n              keyof a] extends true\n          ? true // all values are matching\n          : false\n        : never\n    )\n    ? true\n    : false\n  : b extends a\n  ? true\n  : false;\n"
  },
  {
    "path": "src/types/Match.ts",
    "content": "import type * as symbols from '../internals/symbols';\nimport type { Pattern, MatchedValue } from './Pattern';\nimport type { InvertPatternForExclude, InvertPattern } from './InvertPattern';\nimport type { DeepExclude } from './DeepExclude';\nimport type { Union, GuardValue, IsNever } from './helpers';\nimport type { FindSelected } from './FindSelected';\n\nexport type PickReturnValue<a, b> = a extends symbols.unset ? b : a;\n\ninterface NonExhaustiveError<i> {\n  __nonExhaustive: never;\n}\n\ninterface TSPatternError<i> {\n  __nonExhaustive: never;\n}\n\n/**\n * #### Match\n * An interface to create a pattern matching clause.\n */\nexport type Match<\n  i,\n  o,\n  handledCases extends any[] = [],\n  inferredOutput = never\n> = {\n  /**\n   * `.with(pattern, handler)` Registers a pattern and an handler function that\n   * will be called if the pattern matches the input value.\n   *\n   * [Read the documentation for `.with()` on GitHub](https://github.com/gvergnaud/ts-pattern#with)\n   **/\n  with<\n    const p extends Pattern<i>,\n    c,\n    value extends MatchedValue<i, InvertPattern<p, i>>\n  >(\n    pattern: IsNever<p> extends true\n      ? /**\n         * HACK: Using `IsNever<p>` here is a hack to\n         * make sure the type checker forwards\n         * the input type parameter to pattern\n         * creator functions like `P.when`, `P.not`\n         * `P.union` when they are passed to `.with`\n         * directly.\n         */\n        Pattern<i>\n      : p,\n    handler: (\n      selections: FindSelected<value, p>,\n      value: value\n    ) => PickReturnValue<o, c>\n  ): InvertPatternForExclude<p, value> extends infer excluded\n    ? Match<\n        Exclude<i, excluded>,\n        o,\n        [...handledCases, excluded],\n        Union<inferredOutput, c>\n      >\n    : never;\n\n  with<\n    const p1 extends Pattern<i>,\n    const p2 extends Pattern<i>,\n    c,\n    p extends p1 | p2,\n    value extends p extends any ? MatchedValue<i, InvertPattern<p, i>> : never\n  >(\n    p1: p1,\n    p2: p2,\n    handler: (value: value) => PickReturnValue<o, c>\n  ): [\n    InvertPatternForExclude<p1, value>,\n    InvertPatternForExclude<p2, value>\n  ] extends [infer excluded1, infer excluded2]\n    ? Match<\n        Exclude<i, excluded1 | excluded2>,\n        o,\n        [...handledCases, excluded1, excluded2],\n        Union<inferredOutput, c>\n      >\n    : never;\n\n  with<\n    const p1 extends Pattern<i>,\n    const p2 extends Pattern<i>,\n    const p3 extends Pattern<i>,\n    const ps extends readonly Pattern<i>[],\n    c,\n    p extends p1 | p2 | p3 | ps[number],\n    value extends MatchedValue<i, InvertPattern<p, i>>\n  >(\n    ...args: [\n      p1: p1,\n      p2: p2,\n      p3: p3,\n      ...patterns: ps,\n      handler: (value: value) => PickReturnValue<o, c>\n    ]\n  ): [\n    InvertPatternForExclude<p1, value>,\n    InvertPatternForExclude<p2, value>,\n    InvertPatternForExclude<p3, value>,\n    MakeTuples<ps, value>\n  ] extends [\n    infer excluded1,\n    infer excluded2,\n    infer excluded3,\n    infer excludedRest\n  ]\n    ? Match<\n        Exclude<\n          i,\n          | excluded1\n          | excluded2\n          | excluded3\n          | Extract<excludedRest, any[]>[number]\n        >,\n        o,\n        [\n          ...handledCases,\n          excluded1,\n          excluded2,\n          excluded3,\n          ...Extract<excludedRest, any[]>\n        ],\n        Union<inferredOutput, c>\n      >\n    : never;\n\n  with<\n    const pat extends Pattern<i>,\n    pred extends (value: MatchedValue<i, InvertPattern<pat, i>>) => unknown,\n    c,\n    value extends GuardValue<pred>\n  >(\n    pattern: pat,\n    predicate: pred,\n    handler: (\n      selections: FindSelected<value, pat>,\n      value: value\n    ) => PickReturnValue<o, c>\n  ): pred extends (value: any) => value is infer narrowed\n    ? Match<\n        Exclude<i, narrowed>,\n        o,\n        [...handledCases, narrowed],\n        Union<inferredOutput, c>\n      >\n    : Match<i, o, handledCases, Union<inferredOutput, c>>;\n\n  /**\n   * `.when(predicate, handler)` Registers a predicate function and an handler function.\n   * If the predicate returns true, the handler function will be called.\n   *\n   * [Read the documentation for `.when()` on GitHub](https://github.com/gvergnaud/ts-pattern#when)\n   **/\n  when<pred extends (value: i) => unknown, c, value extends GuardValue<pred>>(\n    predicate: pred,\n    handler: (value: value) => PickReturnValue<o, c>\n  ): pred extends (value: any) => value is infer narrowed\n    ? Match<\n        Exclude<i, narrowed>,\n        o,\n        [...handledCases, narrowed],\n        Union<inferredOutput, c>\n      >\n    : Match<i, o, handledCases, Union<inferredOutput, c>>;\n\n  /**\n   * `.otherwise()` takes a **default handler function** that will be\n   * called if no previous pattern matched your input.\n   *\n   * Equivalent to `.with(P._, () => x).exhaustive()`\n   *\n   * [Read the documentation for `.otherwise()` on GitHub](https://github.com/gvergnaud/ts-pattern#otherwise)\n   *\n   **/\n  otherwise<c>(\n    handler: (value: i) => PickReturnValue<o, c>\n  ): PickReturnValue<o, Union<inferredOutput, c>>;\n\n  /**\n   * `.exhaustive()` checks that all cases are handled, and returns the result value.\n   *\n   * If you get a `NonExhaustiveError`, it means that you aren't handling\n   * all cases. You should probably add another `.with(...)` clause\n   * to match the missing case and prevent runtime errors.\n   *\n   * [Read the documentation for `.exhaustive()` on GitHub](https://github.com/gvergnaud/ts-pattern#exhaustive)\n   *\n   */\n  exhaustive: DeepExcludeAll<i, handledCases> extends infer remainingCases\n    ? [remainingCases] extends [never]\n      ? Exhaustive<o, inferredOutput>\n      : NonExhaustiveError<remainingCases>\n    : never;\n\n  /**\n   * `.run()` return the resulting value.\n   *\n   * ⚠️ calling this function is unsafe, and may throw if no pattern matches your input.\n   */\n  run(): PickReturnValue<o, inferredOutput>;\n\n  /**\n   * `.returnType<T>()` Lets you specify the return type for all of your branches.\n   *\n   * [Read the documentation for `.returnType()` on GitHub](https://github.com/gvergnaud/ts-pattern#returnType)\n   */\n  returnType: [inferredOutput] extends [never]\n    ? <output>() => Match<i, output, handledCases>\n    : TSPatternError<'calling `.returnType<T>()` is only allowed directly after `match(...)`.'>;\n\n  /**\n   * `.narrow()` narrows the input type to exclude all cases that have previously been handled.\n   *\n   * `.narrow()` is only useful if you want to excluded cases from union types or nullable\n   * properties that are deeply nested. Handled cases from top level union types are excluded\n   * by default.\n   *\n   * [Read the documentation for `.narrow() on GitHub](https://github.com/gvergnaud/ts-pattern#narrow)\n   */\n  narrow(): Match<DeepExcludeAll<i, handledCases>, o, [], inferredOutput>;\n};\n\n/**\n * Potential for optimization here:\n *\n * Since DeepExclude distributes the union of the input type, it can\n * generate very large union types on patterns touching several unions at once.\n * If we were sorting patterns from those which distribute the smallest\n * amount of union types to those which distribute the largest, we would eliminate\n * cheap cases more quickly and have less cases in the input type for patterns\n * that will be expensive to exclude.\n *\n * This pre supposes that we have a cheap way of telling if the number\n * of union types a pattern touches and a cheap way of sorting the tuple\n * of patterns.\n * - For the first part, we could reuse `FindMatchingUnions` and pick the `length`\n *   of the returned tuple.\n * - For the second part though I'm not aware a cheap way of sorting a tuple.\n */\ntype DeepExcludeAll<a, tupleList extends any[]> = [a] extends [never]\n  ? never\n  : tupleList extends [infer excluded, ...infer tail]\n  ? DeepExcludeAll<DeepExclude<a, excluded>, tail>\n  : a;\n\ntype MakeTuples<ps extends readonly any[], value> = {\n  -readonly [index in keyof ps]: InvertPatternForExclude<ps[index], value>;\n};\n\n/**\n * The type of an overloaded function for `.exhaustive`,\n * permitting calling it with or without a catch-all handler function.\n *\n * By default, TS-Pattern will throw an error if a runtime value isn't handled.\n */\ntype Exhaustive<output, inferredOutput> = {\n  /**\n   * `.exhaustive()` checks that all cases are handled, and returns the result value.\n   *\n   * If you get a `NonExhaustiveError`, it means that you aren't handling\n   * all cases. You should probably add another `.with(...)` clause\n   * to match the missing case and prevent runtime errors.\n   *\n   * [Read the documentation for `.exhaustive()` on GitHub](https://github.com/gvergnaud/ts-pattern#exhaustive)\n   *\n   */\n  (): PickReturnValue<output, inferredOutput>;\n  /**\n   * `.exhaustive(fallback)` checks that all cases are handled and returns the result value.\n   *\n   * The fallback function will be called if your input value doesn't match any pattern.\n   * This can only happen if the value you passed to `match` has an incorrect type.\n   *\n   * If you get a `NonExhaustiveError`, it means that you aren't handling\n   * all cases. You should probably add another `.with(...)` clause\n   * to match the missing case.\n   *\n   * [Read the documentation for `.exhaustive()` on GitHub](https://github.com/gvergnaud/ts-pattern#exhaustive)\n   */\n  <otherOutput>(\n    handler: (unexpectedValue: unknown) => PickReturnValue<output, otherOutput>\n  ): PickReturnValue<output, Union<inferredOutput, otherOutput>>;\n};\n"
  },
  {
    "path": "src/types/Pattern.ts",
    "content": "import type * as symbols from '../internals/symbols';\nimport { MergeUnion, Primitives, WithDefault } from './helpers';\nimport { None, Some, SelectionType } from './FindSelected';\nimport { matcher } from '../patterns';\nimport { ExtractPreciseValue } from './ExtractPreciseValue';\n\nexport type MatcherType =\n  | 'not'\n  | 'optional'\n  | 'or'\n  | 'and'\n  | 'array'\n  | 'record'\n  | 'map'\n  | 'set'\n  | 'select'\n  | 'default'\n  | 'custom';\n\n// We use a separate MatcherProtocol type to preserves\n// the type level information (selections and excluded) used\n// only for inference.\nexport type MatcherProtocol<\n  input,\n  narrowed,\n  // Type of what this pattern selected from the input\n  matcherType extends MatcherType,\n  selections extends SelectionType,\n  // Type to exclude from the input union because\n  // it has been fully matched by this pattern\n  excluded\n> = {\n  match: <I>(value: I | input) => MatchResult;\n  getSelectionKeys?: () => string[];\n  matcherType?: matcherType;\n};\n\nexport type MatchResult = {\n  matched: boolean;\n  selections?: Record<string, any>;\n};\n\n/**\n * A `Matcher` is an object implementing the match\n * protocol. It must define a `symbols.matcher` property\n * which returns an object with a `match()` method, taking\n * the input value and returning whether the pattern matches\n * or not, along with optional selections.\n */\nexport interface Matcher<\n  input,\n  narrowed,\n  // Type of what this pattern selected from the input\n  matcherType extends MatcherType = 'default',\n  selections extends SelectionType = None,\n  // Type to exclude from the input union because\n  // it has been fully matched by this pattern\n  excluded = narrowed\n> {\n  [matcher](): MatcherProtocol<\n    input,\n    narrowed,\n    matcherType,\n    selections,\n    excluded\n  >;\n  // only used for array matchers\n  [symbols.isVariadic]?: boolean;\n}\n\ntype PatternMatcher<input> = Matcher<input, unknown, any, any>;\n\n// We fall back to `a` if we weren't able to extract anything more precise\nexport type MatchedValue<a, invpattern> = WithDefault<\n  ExtractPreciseValue<a, invpattern>,\n  a\n>;\n\nexport type AnyMatcher = Matcher<any, any, any, any, any>;\n\ntype UnknownMatcher = PatternMatcher<unknown>;\n\nexport type CustomP<input, pattern, narrowedOrFn> = Matcher<\n  input,\n  pattern,\n  //  👆\n  // for the input type to be instantiated correctly\n  // on subpatterns, it has to be passed through.\n  'custom',\n  None,\n  narrowedOrFn\n>;\n\nexport type ArrayP<input, p> = Matcher<input, p, 'array'>;\n\nexport type RecordP<input, pkey, pvalue> = Matcher<\n  input,\n  [pkey, pvalue],\n  'record'\n>;\n\nexport type OptionalP<input, p> = Matcher<input, p, 'optional'>;\n\nexport type MapP<input, pkey, pvalue> = Matcher<input, [pkey, pvalue], 'map'>;\n\nexport type SetP<input, p> = Matcher<input, p, 'set'>;\n\nexport type AndP<input, ps> = Matcher<input, ps, 'and'>;\n\nexport type OrP<input, ps> = Matcher<input, ps, 'or'>;\n\nexport type NotP<input, p> = Matcher<input, p, 'not'>;\n\nexport type GuardP<input, narrowed> = Matcher<input, narrowed>;\n\nexport type GuardExcludeP<input, narrowed, excluded> = Matcher<\n  input,\n  narrowed,\n  'default',\n  None,\n  excluded\n>;\n\nexport type SelectP<\n  key extends string,\n  input = unknown,\n  p = Matcher<unknown, unknown>\n> = Matcher<input, p, 'select', Some<key>>;\n\nexport type AnonymousSelectP = SelectP<symbols.anonymousSelectKey>;\n\nexport interface Override<a> {\n  [symbols.override]: a;\n}\n\nexport type UnknownProperties = { readonly [k: PropertyKey]: unknown };\n\nexport type UnknownValuePattern =\n  | readonly []\n  | readonly [unknown, ...unknown[]]\n  | readonly [...unknown[], unknown]\n  | UnknownProperties\n  | Primitives\n  | UnknownMatcher;\n\n/**\n * `Pattern<a>` is the generic type for patterns matching a value of type `a`. A pattern can be any (nested) javascript value.\n *\n * They can also be wildcards, like `P._`, `P.string`, `P.number`,\n * or other matchers, like `P.when(predicate)`, `P.not(pattern)`, etc.\n *\n * [Read the documentation for `P.Pattern` on GitHub](https://github.com/gvergnaud/ts-pattern#patterns)\n *\n * @example\n * const pattern: P.Pattern<User> = { name: P.string }\n */\nexport type Pattern<a = unknown> = unknown extends a\n  ? UnknownValuePattern\n  : KnownPattern<a>;\n\ntype KnownPattern<a> = KnownPatternInternal<a>;\n\ntype KnownPatternInternal<\n  a,\n  objs = Exclude<a, Primitives | Map<any, any> | Set<any> | readonly any[]>,\n  arrays = Extract<a, readonly any[]>,\n  primitives = Extract<a, Primitives>\n> =\n  | primitives\n  | PatternMatcher<a>\n  | ([objs] extends [never] ? never : ObjectPattern<Readonly<MergeUnion<objs>>>)\n  | ([arrays] extends [never] ? never : ArrayPattern<arrays>);\n\ntype ObjectPattern<a> =\n  | {\n      readonly [k in keyof a]?: Pattern<a[k]>;\n    }\n  | never;\n\ntype ArrayPattern<a> = a extends readonly (infer i)[]\n  ? a extends readonly [any, ...any]\n    ? { readonly [index in keyof a]: Pattern<a[index]> }\n    :\n        | readonly []\n        | readonly [Pattern<i>, ...Pattern<i>[]]\n        | readonly [...Pattern<i>[], Pattern<i>]\n  : never;\n\n// These aliases could be inferred, but lead to nicer display names in IDEs.\nexport type UnknownPattern = Chainable<GuardP<unknown, unknown>, never>;\nexport type StringPattern = StringChainable<GuardP<unknown, string>, never>;\nexport type NumberPattern = NumberChainable<GuardP<unknown, number>, never>;\nexport type BooleanPattern = Chainable<GuardP<unknown, boolean>, never>;\nexport type BigIntPattern = BigIntChainable<GuardP<unknown, bigint>, never>;\nexport type SymbolPattern = Chainable<GuardP<unknown, symbol>, never>;\nexport type NullishPattern = Chainable<\n  GuardP<unknown, null | undefined>,\n  never\n>;\n\nexport type NonNullablePattern = Chainable<GuardP<unknown, {}>, never>;\n\ntype MergeGuards<input, guard1, guard2> = [guard1, guard2] extends [\n  GuardExcludeP<any, infer narrowed1, infer excluded1>,\n  GuardExcludeP<any, infer narrowed2, infer excluded2>\n]\n  ? GuardExcludeP<input, narrowed1 & narrowed2, excluded1 & excluded2>\n  : never;\n\nexport type Chainable<p, omitted extends string = never> = p &\n  Omit<\n    {\n      /**\n       * `.optional()` returns a pattern which matches if the\n       * key is undefined or if it is defined and the previous pattern matches its value.\n       *\n       * [Read the documentation for `P.optional` on GitHub](https://github.com/gvergnaud/ts-pattern#poptional-patterns)\n       *\n       * @example\n       *  match(value)\n       *   .with({ greeting: P.string.optional() }, () => 'will match { greeting?: string}')\n       */\n      optional<input>(): Chainable<OptionalP<input, p>, omitted | 'optional'>;\n      /**\n       * `pattern.and(pattern)` returns a pattern that matches\n       * if the previous pattern and the next one match the input.\n       *\n       * [Read the documentation for `P.intersection` on GitHub](https://github.com/gvergnaud/ts-pattern#pintersection-patterns)\n       *\n       * @example\n       *  match(value)\n       *   .with(\n       *     P.string.and(P.when(isUsername)),\n       *     (username) => '...'\n       *   )\n       */\n      and<input, const p2 extends Pattern<input>>(\n        pattern: p2\n      ): Chainable<AndP<input, [p, p2]>, omitted>;\n      /**\n       * `pattern.or(pattern)` returns a pattern that matches\n       * if **either** the previous pattern or the next one match the input.\n       *\n       * [Read the documentation for `P.union` on GitHub](https://github.com/gvergnaud/ts-pattern#punion-patterns)\n       *\n       * @example\n       *  match(value)\n       *   .with(\n       *     { value: P.string.or(P.number) },\n       *     ({ value }) => 'value: number | string'\n       *   )\n       */\n      or<input, const p2 extends Pattern<input>>(\n        pattern: p2\n      ): Chainable<OrP<input, [p, p2]>, omitted>;\n      /**\n       * `P.select()` will inject this property into the handler function's arguments.\n       *\n       * [Read the documentation for `P.select` on GitHub](https://github.com/gvergnaud/ts-pattern#pselect-patterns)\n       *\n       * @example\n       *  match<{ age: number }>(value)\n       *   .with({ age: P.string.select() }, (age) => 'age: number')\n       */\n      select<input>(): Chainable<\n        SelectP<symbols.anonymousSelectKey, input, p>,\n        omitted | 'select' | 'or' | 'and'\n      >;\n      select<input, k extends string>(\n        key: k\n      ): Chainable<SelectP<k, input, p>, omitted | 'select' | 'or' | 'and'>;\n    },\n    omitted\n  >;\n\nexport type StringChainable<\n  p extends Matcher<any, any, any, any, any>,\n  omitted extends string = never\n> = Chainable<p, omitted> &\n  Omit<\n    {\n      /**\n       * `P.string.startsWith(start)` is a pattern, matching **strings** starting with `start`.\n       *\n       * [Read the documentation for `P.string.startsWith` on GitHub](https://github.com/gvergnaud/ts-pattern#pstringstartsWith)\n       *\n       * @example\n       *  match(value)\n       *   .with(P.string.startsWith('A'), () => 'value starts with an A')\n       */\n      startsWith<input, const start extends string>(\n        start: start\n      ): StringChainable<\n        MergeGuards<input, p, GuardP<unknown, `${start}${string}`>>,\n        omitted | 'startsWith'\n      >;\n      /**\n       * `P.string.endsWith(end)` is a pattern, matching **strings** ending with `end`.\n       *\n       * [Read the documentation for `P.string.endsWith` on GitHub](https://github.com/gvergnaud/ts-pattern#pstringendsWith)\n       *\n       * @example\n       *  match(value)\n       *   .with(P.string.endsWith('!'), () => 'value ends with an !')\n       */\n      endsWith<input, const end extends string>(\n        end: end\n      ): StringChainable<\n        MergeGuards<input, p, GuardP<unknown, `${string}${end}`>>,\n        omitted | 'endsWith'\n      >;\n      /**\n       * `P.string.minLength(min)` is a pattern, matching **strings** with at least `min` characters.\n       *\n       * [Read the documentation for `P.string.minLength` on GitHub](https://github.com/gvergnaud/ts-pattern#pstringminLength)\n       *\n       * @example\n       *  match(value)\n       *   .with(P.string.minLength(10), () => 'string with more length <= 10')\n       */\n      minLength<input, const min extends number>(\n        min: min\n      ): StringChainable<\n        MergeGuards<input, p, GuardExcludeP<unknown, string, never>>,\n        omitted | 'minLength'\n      >;\n      /**\n       * `P.string.length(len)` is a pattern, matching **strings** with exactly `len` characters.\n       *\n       * [Read the documentation for `P.string.length` on GitHub](https://github.com/gvergnaud/ts-pattern#pstringlength)\n       *\n       * @example\n       *  match(value)\n       *   .with(P.string.length(10), () => 'strings with length === 10')\n       */\n      length<input, const len extends number>(\n        len: len\n      ): StringChainable<\n        MergeGuards<input, p, GuardExcludeP<unknown, string, never>>,\n        omitted | 'length' | 'minLength' | 'maxLength'\n      >;\n      /**\n       * `P.string.maxLength(max)` is a pattern, matching **strings** with at most `max` characters.\n       *\n       * [Read the documentation for `P.string.maxLength` on GitHub](https://github.com/gvergnaud/ts-pattern#pstringmaxLength)\n       *\n       * @example\n       *  match(value)\n       *   .with(P.string.maxLength(10), () => 'string with more length >= 10')\n       */\n      maxLength<input, const max extends number>(\n        max: max\n      ): StringChainable<\n        MergeGuards<input, p, GuardExcludeP<unknown, string, never>>,\n        omitted | 'maxLength'\n      >;\n      /**\n       * `P.string.includes(substr)` is a pattern, matching **strings** containing `substr`.\n       *\n       * [Read the documentation for `P.string.includes` on GitHub](https://github.com/gvergnaud/ts-pattern#pstringincludes)\n       *\n       * @example\n       *  match(value)\n       *   .with(P.string.includes('http'), () => 'value contains http')\n       */\n      includes<input, const substr extends string>(\n        substr: substr\n      ): StringChainable<\n        MergeGuards<input, p, GuardExcludeP<unknown, string, never>>,\n        omitted\n      >;\n      /**\n       * `P.string.regex(expr)` is a pattern, matching **strings** that `expr` regular expression.\n       *\n       * [Read the documentation for `P.string.regex` on GitHub](https://github.com/gvergnaud/ts-pattern#pstringregex)\n       *\n       * @example\n       *  match(value)\n       *   .with(P.string.regex(/^https?:\\/\\//), () => 'url')\n       */\n      regex<input, const expr extends string | RegExp>(\n        expr: expr\n      ): StringChainable<\n        MergeGuards<input, p, GuardExcludeP<unknown, string, never>>,\n        omitted\n      >;\n    },\n    omitted\n  >;\n\nexport type NumberChainable<p, omitted extends string = never> = Chainable<\n  p,\n  omitted\n> &\n  Omit<\n    {\n      /**\n       * `P.number.between(min, max)` matches **number** between `min` and `max`,\n       * equal to min or equal to max.\n       *\n       * [Read the documentation for `P.number.between` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumberbetween)\n       *\n       * @example\n       *  match(value)\n       *   .with(P.number.between(0, 10), () => '0 <= numbers <= 10')\n       */\n      between<input, const min extends number, const max extends number>(\n        min: min,\n        max: max\n      ): NumberChainable<\n        MergeGuards<input, p, GuardExcludeP<unknown, number, never>>,\n        omitted\n      >;\n      /**\n       * `P.number.lt(max)` matches **number** smaller than `max`.\n       *\n       * [Read the documentation for `P.number.lt` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumberlt)\n       *\n       * @example\n       *  match(value)\n       *   .with(P.number.lt(10), () => 'numbers < 10')\n       */\n      lt<input, const max extends number>(\n        max: max\n      ): NumberChainable<\n        MergeGuards<input, p, GuardExcludeP<unknown, number, never>>,\n        omitted\n      >;\n      /**\n       * `P.number.gt(min)` matches **number** greater than `min`.\n       *\n       * [Read the documentation for `P.number.gt` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumbergt)\n       *\n       * @example\n       *  match(value)\n       *   .with(P.number.gt(10), () => 'numbers > 10')\n       */\n      gt<input, const min extends number>(\n        min: min\n      ): NumberChainable<\n        MergeGuards<input, p, GuardExcludeP<unknown, number, never>>,\n        omitted\n      >;\n      /**\n       * `P.number.lte(max)` matches **number** smaller than or equal to `max`.\n       *\n       * [Read the documentation for `P.number.lte` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumberlte)\n       *\n       * @example\n       *  match(value)\n       *   .with(P.number.lte(10), () => 'numbers <= 10')\n       */\n      lte<input, const max extends number>(\n        max: max\n      ): NumberChainable<\n        MergeGuards<input, p, GuardExcludeP<unknown, number, never>>,\n        omitted\n      >;\n      /**\n       * `P.number.gte(min)` matches **number** greater than or equal to `min`.\n       *\n       * [Read the documentation for `P.number.gte` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumbergte)\n       *\n       * @example\n       *  match(value)\n       *   .with(P.number.gte(10), () => 'numbers >= 10')\n       */\n      gte<input, const min extends number>(\n        min: min\n      ): NumberChainable<\n        MergeGuards<input, p, GuardExcludeP<unknown, number, never>>,\n        omitted\n      >;\n      /**\n       * `P.number.int` matches **integer** numbers.\n       *\n       * [Read the documentation for `P.number.int` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumberint)\n       *\n       * @example\n       *  match(value)\n       *   .with(P.number.int, () => 'an integer')\n       */\n      int<input>(): NumberChainable<\n        MergeGuards<input, p, GuardExcludeP<unknown, number, never>>,\n        omitted | 'int'\n      >;\n      /**\n       * `P.number.finite` matches **finite numbers**.\n       *\n       * [Read the documentation for `P.number.finite` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumberfinite)\n       *\n       * @example\n       *  match(value)\n       *   .with(P.number.finite, () => 'not Infinity')\n       */\n      finite<input>(): NumberChainable<\n        MergeGuards<input, p, GuardExcludeP<unknown, number, never>>,\n        omitted | 'finite'\n      >;\n      /**\n       * `P.number.positive` matches **positive** numbers.\n       *\n       * [Read the documentation for `P.number.positive` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumberpositive)\n       *\n       * @example\n       *  match(value)\n       *   .with(P.number.positive, () => 'number > 0')\n       */\n      positive<input>(): NumberChainable<\n        MergeGuards<input, p, GuardExcludeP<unknown, number, never>>,\n        omitted | 'positive' | 'negative'\n      >;\n      /**\n       * `P.number.negative` matches **negative** numbers.\n       *\n       * [Read the documentation for `P.number.negative` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumbernegative)\n       *\n       * @example\n       *  match(value)\n       *   .with(P.number.negative, () => 'number < 0')\n       */\n      negative<input>(): NumberChainable<\n        MergeGuards<input, p, GuardExcludeP<unknown, number, never>>,\n        omitted | 'positive' | 'negative' | 'negative'\n      >;\n    },\n    omitted\n  >;\n\nexport type BigIntChainable<p, omitted extends string = never> = Chainable<\n  p,\n  omitted\n> &\n  Omit<\n    {\n      /**\n       * `P.bigint.between(min, max)` matches **bigint** between `min` and `max`,\n       * equal to min or equal to max.\n       *\n       * [Read the documentation for `P.bigint.between` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumberbetween)\n       *\n       * @example\n       *  match(value)\n       *   .with(P.bigint.between(0, 10), () => '0 <= numbers <= 10')\n       */\n      between<input, const min extends bigint, const max extends bigint>(\n        min: min,\n        max: max\n      ): BigIntChainable<\n        MergeGuards<input, p, GuardExcludeP<unknown, bigint, never>>,\n        omitted\n      >;\n      /**\n       * `P.bigint.lt(max)` matches **bigint** smaller than `max`.\n       *\n       * [Read the documentation for `P.bigint.lt` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumberlt)\n       *\n       * @example\n       *  match(value)\n       *   .with(P.bigint.lt(10), () => 'numbers < 10')\n       */\n      lt<input, const max extends bigint>(\n        max: max\n      ): BigIntChainable<\n        MergeGuards<input, p, GuardExcludeP<unknown, bigint, never>>,\n        omitted\n      >;\n      /**\n       * `P.bigint.gt(min)` matches **bigint** greater than `min`.\n       *\n       * [Read the documentation for `P.bigint.gt` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumbergt)\n       *\n       * @example\n       *  match(value)\n       *   .with(P.bigint.gt(10), () => 'numbers > 10')\n       */\n      gt<input, const min extends bigint>(\n        min: min\n      ): BigIntChainable<\n        MergeGuards<input, p, GuardExcludeP<unknown, bigint, never>>,\n        omitted\n      >;\n      /**\n       * `P.bigint.lte(max)` matches **bigint** smaller than or equal to `max`.\n       *\n       * [Read the documentation for `P.bigint.lte` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumberlte)\n       *\n       * @example\n       *  match(value)\n       *   .with(P.bigint.lte(10), () => 'bigints <= 10')\n       */\n      lte<input, const max extends bigint>(\n        max: max\n      ): BigIntChainable<\n        MergeGuards<input, p, GuardExcludeP<unknown, bigint, never>>,\n        omitted\n      >;\n      /**\n       * `P.bigint.gte(min)` matches **bigint** greater than or equal to `min`.\n       *\n       * [Read the documentation for `P.bigint.gte` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumbergte)\n       *\n       * @example\n       *  match(value)\n       *   .with(P.bigint.gte(10), () => 'bigints >= 10')\n       */\n      gte<input, const min extends bigint>(\n        min: min\n      ): BigIntChainable<\n        MergeGuards<input, p, GuardExcludeP<unknown, bigint, never>>,\n        omitted\n      >;\n      /**\n       * `P.bigint.positive` matches **positive** bigints.\n       *\n       * [Read the documentation for `P.bigint.positive` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumberpositive)\n       *\n       * @example\n       *  match(value)\n       *   .with(P.bigint.positive, () => 'bigint > 0')\n       */\n      positive<input>(): BigIntChainable<\n        MergeGuards<input, p, GuardExcludeP<unknown, bigint, never>>,\n        omitted | 'positive' | 'negative'\n      >;\n      /**\n       * `P.bigint.negative` matches **negative** bigints.\n       *\n       * [Read the documentation for `P.bigint.negative` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumbernegative)\n       *\n       * @example\n       *  match(value)\n       *   .with(P.bigint.negative, () => 'bigint < 0')\n       */\n      negative<input>(): BigIntChainable<\n        MergeGuards<input, p, GuardExcludeP<unknown, bigint, never>>,\n        omitted | 'positive' | 'negative' | 'negative'\n      >;\n    },\n    omitted\n  >;\n\nexport type Variadic<pattern> = pattern & Iterable<pattern>;\n\nexport type ArrayChainable<\n  pattern,\n  omitted extends string = never\n> = Variadic<pattern> &\n  Omit<\n    {\n      /**\n       * `.optional()` returns a pattern which matches if the\n       * key is undefined or if it is defined and the previous pattern matches its value.\n       *\n       * [Read the documentation for `P.optional` on GitHub](https://github.com/gvergnaud/ts-pattern#poptional-patterns)\n       *\n       * @example\n       *  match(value)\n       *   .with({ greeting: P.string.optional() }, () => 'will match { greeting?: string}')\n       */\n      optional<input>(): ArrayChainable<\n        OptionalP<input, pattern>,\n        omitted | 'optional'\n      >;\n      /**\n       * `P.select()` will inject this property into the handler function's arguments.\n       *\n       * [Read the documentation for `P.select` on GitHub](https://github.com/gvergnaud/ts-pattern#pselect-patterns)\n       *\n       * @example\n       *  match<{ age: number }>(value)\n       *   .with({ age: P.string.select() }, (age) => 'age: number')\n       */\n      select<input>(): ArrayChainable<\n        SelectP<symbols.anonymousSelectKey, input, pattern>,\n        omitted | 'select'\n      >;\n      select<input, k extends string>(\n        key: k\n      ): ArrayChainable<SelectP<k, input, pattern>, omitted | 'select'>;\n    },\n    omitted\n  >;\n"
  },
  {
    "path": "src/types/helpers.ts",
    "content": "export type ValueOf<a> = a extends readonly any[] ? a[number] : a[keyof a];\n\nexport type Values<a extends object> = UnionToTuple<ValueOf<a>>;\n\n/**\n * ### LeastUpperBound\n * An interesting one. A type taking two imbricated sets and returning the\n * smallest one.\n * We need that because sometimes the pattern's inferred type holds more\n * information than the value on which we are matching (if the value is any\n * or unknown for instance).\n */\n\nexport type LeastUpperBound<a, b> = b extends a ? b : a extends b ? a : never;\n\nexport type Contains<a, b> = a extends any\n  ? 'exclude' extends {\n      [k in keyof a]-?: Equal<a[k], b> extends true ? 'exclude' : 'include';\n    }[keyof a]\n    ? true\n    : false\n  : never;\n\n// from https://stackoverflow.com/questions/50374908/transform-union-type-to-intersection-type/50375286#50375286\nexport type UnionToIntersection<union> = (\n  union extends any ? (k: union) => void : never\n) extends (k: infer intersection) => void\n  ? intersection\n  : never;\n\nexport type IsUnion<a> = [a] extends [UnionToIntersection<a>] ? false : true;\n\nexport type UnionToTuple<\n  union,\n  output extends any[] = []\n> = UnionToIntersection<\n  union extends any ? (t: union) => union : never\n> extends (_: any) => infer elem\n  ? UnionToTuple<Exclude<union, elem>, [elem, ...output]>\n  : output;\n\nexport type Flatten<\n  xs extends readonly any[],\n  output extends any[] = []\n> = xs extends readonly [infer head, ...infer tail]\n  ? Flatten<tail, [...output, ...Extract<head, readonly any[]>]>\n  : output;\n\nexport type Equal<a, b> = (<T>() => T extends a ? 1 : 2) extends <\n  T\n>() => T extends b ? 1 : 2\n  ? true\n  : false;\n\nexport type Expect<a extends true> = a;\n\nexport type IsAny<a> = 0 extends 1 & a ? true : false;\n\nexport type IsNever<T> = [T] extends [never] ? true : false;\n\nexport type Length<it extends readonly any[]> = it['length'];\n\nexport type Iterator<\n  n extends number,\n  it extends any[] = []\n> = it['length'] extends n ? it : Iterator<n, [any, ...it]>;\n\nexport type Next<it extends any[]> = [any, ...it];\nexport type Prev<it extends any[]> = it extends readonly [any, ...infer tail]\n  ? tail\n  : [];\n\nexport type Take<\n  xs extends readonly any[],\n  it extends any[],\n  output extends any[] = []\n> = Length<it> extends 0\n  ? output\n  : xs extends readonly [infer head, ...infer tail]\n  ? Take<tail, Prev<it>, [...output, head]>\n  : output;\n\nexport type Drop<\n  xs extends readonly any[],\n  n extends any[]\n> = Length<n> extends 0\n  ? xs\n  : xs extends readonly [any, ...infer tail]\n  ? Drop<tail, Prev<n>>\n  : [];\n\nexport type UpdateAt<\n  tail extends readonly any[],\n  n extends any[],\n  value,\n  inits extends readonly any[] = []\n> = Length<n> extends 0\n  ? tail extends readonly [any, ...infer tail]\n    ? [...inits, value, ...tail]\n    : inits\n  : tail extends readonly [infer head, ...infer tail]\n  ? UpdateAt<tail, Prev<n>, value, [...inits, head]>\n  : inits;\n\nexport type BuiltInObjects =\n  | Function\n  | Date\n  | RegExp\n  | Generator\n  | { readonly [Symbol.toStringTag]: string }\n  | any[];\n\nexport type IsPlainObject<o, excludeUnion = BuiltInObjects> = o extends object\n  ? // to excluded branded string types,\n    // like `string & { __brand: \"id\" }`\n    // and built-in objects\n    o extends string | excludeUnion\n    ? false\n    : true\n  : false;\n\nexport type Compute<a extends any> = a extends BuiltInObjects\n  ? a\n  : { [k in keyof a]: a[k] };\n\nexport type IntersectObjects<a> = (\n  a extends any ? keyof a : never\n) extends infer allKeys\n  ? {\n      [k in Extract<allKeys, PropertyKey>]: a extends any\n        ? k extends keyof a\n          ? a[k]\n          : never\n        : never;\n    }\n  : never;\n\nexport type WithDefault<a, def> = [a] extends [never] ? def : a;\n\nexport type IsLiteral<a> = [a] extends [null | undefined]\n  ? true\n  : [a] extends [string]\n  ? string extends a\n    ? false\n    : true\n  : [a] extends [number]\n  ? number extends a\n    ? false\n    : true\n  : [a] extends [boolean]\n  ? boolean extends a\n    ? false\n    : true\n  : [a] extends [symbol]\n  ? symbol extends a\n    ? false\n    : true\n  : [a] extends [bigint]\n  ? bigint extends a\n    ? false\n    : true\n  : false;\n\nexport type Primitives =\n  | number\n  | boolean\n  | string\n  | undefined\n  | null\n  | symbol\n  | bigint;\n\nexport type NonLiteralPrimitive = Exclude<Primitives, undefined | null>;\n\nexport type TupleKeys = '0' | '1' | '2' | '3' | '4';\n\nexport type Union<a, b> = [b] extends [a] ? a : [a] extends [b] ? b : a | b;\n\n/**\n * GuardValue returns the value guarded by a type guard function.\n */\nexport type GuardValue<fn> = fn extends (value: any) => value is infer b\n  ? b\n  : fn extends (value: infer a) => unknown\n  ? a\n  : never;\n\nexport type GuardFunction<input, narrowed> =\n  | ((value: input) => value is Extract<narrowed, input>)\n  | ((value: input) => boolean);\n\nexport type Some<bools extends boolean[]> = true extends bools[number]\n  ? true\n  : false;\n\nexport type All<bools extends boolean[]> = bools[number] extends true\n  ? true\n  : false;\n\nexport type Extends<a, b> = [a] extends [b] ? true : false;\n\nexport type Not<a extends boolean> = a extends true ? false : true;\n\ntype AllKeys<a> = a extends any ? keyof a : never;\n\n// Merge unions of objects into a single object with unions of keys\nexport type MergeUnion<a> =\n  | {\n      [k in AllKeys<a>]: a extends any\n        ? k extends keyof a\n          ? a[k]\n          : never\n        : never;\n    }\n  | never;\n\nexport type IsFixedSizeTuple<a extends readonly any[]> = IsLiteral<Length<a>>;\n\n// is it a fixed size or a variadic tuple\nexport type IsTuple<a> = a extends\n  | readonly []\n  | readonly [any, ...any]\n  | readonly [...any, any]\n  ? true\n  : false;\n\nexport type IsStrictArray<a extends readonly any[]> = Not<IsTuple<a>>;\n\nexport type IsReadonlyArray<a> = a extends readonly any[]\n  ? a extends any[] // mutable array\n    ? false\n    : true\n  : false;\n\nexport type MaybeAddReadonly<\n  a,\n  shouldAdd extends boolean\n> = shouldAdd extends true ? Readonly<a> : a;\n\nexport type MapKey<T> = T extends Map<infer K, any> ? K : never;\n\nexport type MapValue<T> = T extends Map<any, infer V> ? V : never;\n\nexport type SetValue<T> = T extends Set<infer V> ? V : never;\n\nexport type RecordKey<T> = T extends Record<infer K, any> ? K : never;\n\nexport type RecordValue<T> = T extends Record<any, infer V> ? V : never;\n\nexport type ReadonlyArrayValue<T> = T extends ReadonlyArray<infer V>\n  ? V\n  : never;\n\nexport type ExtractPlainObject<T> = T extends any\n  ? IsPlainObject<T> extends true\n    ? T\n    : never\n  : never;\n\nexport type GetKey<O, K> = O extends any\n  ? K extends keyof O\n    ? O[K]\n    : never\n  : never;\n\nexport interface Fn {\n  input: unknown;\n  output: unknown;\n}\n\nexport type Call<fn extends Fn, input> = (fn & {\n  input: input;\n})['output'];\n\nexport type IsOptionalKeysOf<obj, key extends keyof obj> = {} extends Pick<\n  obj,\n  key\n>\n  ? true\n  : false;\n"
  },
  {
    "path": "src/types/index.ts",
    "content": "export * from './Pattern';"
  },
  {
    "path": "tests/bigints.test.ts",
    "content": "import { P, match } from '../src';\nimport { Equal, Expect } from '../src/types/helpers';\n\ndescribe('BigInts', () => {\n  it(`P.bigint.between(1, 10)`, () => {\n    const f = (input: string | bigint) =>\n      match(input)\n        .with(P.bigint.between(0n, 10n), (value) => {\n          type t = Expect<Equal<typeof value, bigint>>;\n          return 'between 0 and 10';\n        })\n        .otherwise((value) => {\n          type t = Expect<Equal<typeof value, string | bigint>>;\n          return 'something else';\n        });\n\n    expect(f(5n)).toBe('between 0 and 10');\n    expect(f(0n)).toBe('between 0 and 10');\n    expect(f(10n)).toBe('between 0 and 10');\n    expect(f('gabriel')).toBe('something else');\n  });\n\n  it(`P.bigint.lt(..)`, () => {\n    const f = (input: string | bigint) =>\n      match(input)\n        .with(P.bigint.lt(10n), (value) => {\n          type t = Expect<Equal<typeof value, bigint>>;\n          return 'yes';\n        })\n        .otherwise((value) => {\n          type t = Expect<Equal<typeof value, string | bigint>>;\n          return 'no';\n        });\n\n    expect(f(5n)).toBe('yes');\n    expect(f(12n)).toBe('no');\n    expect(f(10n)).toBe('no');\n  });\n  it(`P.bigint.gt(..)`, () => {\n    const f = (input: string | bigint) =>\n      match(input)\n        .with(P.bigint.gt(10n), (value) => {\n          type t = Expect<Equal<typeof value, bigint>>;\n          return 'yes';\n        })\n        .otherwise((value) => {\n          type t = Expect<Equal<typeof value, string | bigint>>;\n          return 'no';\n        });\n\n    expect(f(5n)).toBe('no');\n    expect(f(10n)).toBe('no');\n    expect(f(12n)).toBe('yes');\n  });\n  it(`P.bigint.gte(..)`, () => {\n    const f = (input: string | bigint) =>\n      match(input)\n        .with(P.bigint.gte(10n), (value) => {\n          type t = Expect<Equal<typeof value, bigint>>;\n          return 'yes';\n        })\n        .otherwise((value) => {\n          type t = Expect<Equal<typeof value, string | bigint>>;\n          return 'no';\n        });\n\n    expect(f(5n)).toBe('no');\n    expect(f(10n)).toBe('yes');\n    expect(f(12n)).toBe('yes');\n  });\n  it(`P.bigint.lte(..)`, () => {\n    const f = (input: string | bigint) =>\n      match(input)\n        .with(P.bigint.lte(10n), (value) => {\n          type t = Expect<Equal<typeof value, bigint>>;\n          return 'yes';\n        })\n        .otherwise((value) => {\n          type t = Expect<Equal<typeof value, string | bigint>>;\n          return 'no';\n        });\n\n    expect(f(5n)).toBe('yes');\n    expect(f(10n)).toBe('yes');\n    expect(f(12n)).toBe('no');\n  });\n  it(`P.bigint.positive()`, () => {\n    const f = (input: string | bigint) =>\n      match(input)\n        .with(P.bigint.positive(), (value) => {\n          type t = Expect<Equal<typeof value, bigint>>;\n          return 'yes';\n        })\n        .otherwise((value) => {\n          type t = Expect<Equal<typeof value, string | bigint>>;\n          return 'no';\n        });\n\n    expect(f(5n)).toBe('yes');\n    expect(f(10123n)).toBe('yes');\n    expect(f(-10123n)).toBe('no');\n  });\n  it(`P.bigint.negative()`, () => {\n    const f = (input: string | bigint) =>\n      match(input)\n        .with(P.bigint.negative(), (value) => {\n          type t = Expect<Equal<typeof value, bigint>>;\n          return 'yes';\n        })\n        .otherwise((value) => {\n          type t = Expect<Equal<typeof value, string | bigint>>;\n          return 'no';\n        });\n\n    expect(f(5n)).toBe('no');\n    expect(f(10123n)).toBe('no');\n    expect(f(-10123n)).toBe('yes');\n  });\n});\n"
  },
  {
    "path": "tests/branded-nominal-types.test.ts",
    "content": "import { match, P } from '../src';\n\ndescribe('Branded strings', () => {\n  type BrandedId = string & { __brand: 'brandId' };\n  type FooBar = { type: 'foo'; id: BrandedId; value: string } | { type: 'bar' };\n  type State = {\n    fooBar: FooBar;\n    fooBarId: BrandedId;\n  };\n\n  it('should treat branded strings as default string, and not as objects', () => {\n    const state: State = {\n      fooBar: { type: 'foo', id: '' as BrandedId, value: 'value' },\n      fooBarId: '' as BrandedId,\n    };\n\n    expect(\n      match(state)\n        .with(\n          { fooBar: { type: 'foo' }, fooBarId: P.when((id) => id === '') },\n          (x) => `Match: ${x.fooBar.value}`\n        )\n        .otherwise(() => 'nope')\n    ).toEqual('Match: value');\n  });\n\n  it('issue #167', () => {\n    const tag: unique symbol = Symbol();\n    type Tagged<Token> = { readonly [tag]: Token };\n    type Opaque<Type, Token = unknown> = Type & Tagged<Token>;\n\n    const opaqueString = (Math.random() > 0.5 ? 'A' : 'B') as Opaque<'A' | 'B'>;\n\n    match(opaqueString)\n      .with('A' as Opaque<'A'>, () => 1)\n      .with('B' as Opaque<'B'>, () => 2)\n      .exhaustive();\n  });\n\n  it('issue #178', () => {\n    const symbol: unique symbol = Symbol();\n\n    interface Branded<key extends string> {\n      [symbol]: { [k in key]: true };\n    }\n\n    type Brand<a, key extends string> = a & Branded<key>;\n    type BrandId = Brand<number, 'BrandId'>;\n\n    const a: number = 1;\n    const b: BrandId = 1 as BrandId;\n\n    expect(\n      match({ a, b })\n        .with({ a, b }, () => '1')\n        .with({ a: P.number, b: P.number }, () => '2')\n        .exhaustive()\n    ).toEqual('1');\n  });\n});\n"
  },
  {
    "path": "tests/build-many.test.ts",
    "content": "import { BuildMany } from '../src/types/BuildMany';\nimport { Equal, Expect } from '../src/types/helpers';\nimport { State } from './types-catalog/utils';\n\ndescribe('BuildMany', () => {\n  it('should correctly update the content of a readonly tuple', () => {\n    type cases = [\n      Expect<\n        Equal<\n          BuildMany<readonly [number, State], [[{ status: 'idle' }, [1]]]>,\n          [number, { status: 'idle' }]\n        >\n      >,\n      Expect<\n        Equal<\n          BuildMany<\n            readonly [number, State],\n            [[{ status: 'idle' }, [1]]] | [[{ status: 'loading' }, [1]]]\n          >,\n          [number, { status: 'idle' }] | [number, { status: 'loading' }]\n        >\n      >\n    ];\n  });\n});\n"
  },
  {
    "path": "tests/chainable.test.ts",
    "content": "import { P, match } from '../src';\nimport { Equal, Expect } from '../src/types/helpers';\n\ndescribe('chainable methods', () => {\n  describe('string compositions', () => {\n    it(`P.string.optional()`, () => {\n      const f = (input?: string | number) =>\n        match(input)\n          .with(P.string.optional(), (value) => {\n            type t = Expect<Equal<typeof value, string | undefined>>;\n            return `yes ${value}`;\n          })\n          .otherwise((value) => {\n            type t = Expect<Equal<typeof value, number>>;\n            return 'no';\n          });\n\n      expect(f(102)).toBe('no');\n      expect(f()).toBe('yes undefined');\n      expect(f('gabriel')).toBe('yes gabriel');\n    });\n\n    it(`P.string.select()`, () => {\n      const f = (input?: string | number) =>\n        match({ input })\n          .with({ input: P.string.select() }, (value) => {\n            type t = Expect<Equal<typeof value, string>>;\n            return `yes ${value}`;\n          })\n          .otherwise(() => 'no');\n\n      expect(f(102)).toBe('no');\n      expect(f()).toBe('no');\n      expect(f('gabriel')).toBe('yes gabriel');\n    });\n    it(`P.number.optional.select()`, () => {\n      const f = (input?: string | number) =>\n        match({ input })\n          .with({ input: P.number.optional().select() }, (value) => {\n            type t = Expect<Equal<typeof value, number | undefined>>;\n            return `yes ${value}`;\n          })\n          .otherwise(() => 'no');\n\n      expect(f(102)).toBe('yes 102');\n      expect(f()).toBe('yes undefined');\n      expect(f('gabriel')).toBe('no');\n    });\n    it(`P.string.optional.select()`, () => {\n      const f = (input?: string | number) =>\n        match({ input })\n          .with({ input: P.string.optional().select() }, (value) => {\n            type t = Expect<Equal<typeof value, string | undefined>>;\n            return `yes ${value}`;\n          })\n          .otherwise(() => 'no');\n\n      expect(f(102)).toBe('no');\n      expect(f()).toBe('yes undefined');\n      expect(f('gabriel')).toBe('yes gabriel');\n    });\n    it(`P.string.startsWith(..).optional().select()`, () => {\n      const f = (input?: string | number) =>\n        match({ input })\n          .with(\n            {\n              input: P.string.startsWith('hello ').optional().select(),\n            },\n            (value) => {\n              type t = Expect<\n                Equal<typeof value, `hello ${string}` | undefined>\n              >;\n              return `starts with hello: ${value}`;\n            }\n          )\n          .otherwise(() => 'no');\n\n      expect(f('hello gabriel')).toBe('starts with hello: hello gabriel');\n      expect(f('gabriel')).toBe('no');\n    });\n\n    it('P.string.startsWith(..).endsWith(..)', () => {\n      const f = (input?: string | number) =>\n        match(input)\n          .with(P.string.startsWith('hello ').endsWith('!'), (value) => {\n            type t = Expect<\n              Equal<typeof value, `hello ${string}` & `${string}!`>\n            >;\n            return `yes: ${value}`;\n          })\n          .otherwise(() => 'no');\n\n      expect(f('hello gabriel!')).toBe('yes: hello gabriel!');\n      expect(f('hello gabriel')).toBe('no');\n      expect(f('gabriel!')).toBe('no');\n      expect(f('gabriel')).toBe('no');\n    });\n  });\n\n  describe('number compositions', () => {\n    it(`P.number.optional()`, () => {\n      const f = (input?: string | number) =>\n        match(input)\n          .with(P.number.optional(), (value) => {\n            type t = Expect<Equal<typeof value, number | undefined>>;\n            return `yes ${value}`;\n          })\n          .otherwise((value) => {\n            type t = Expect<Equal<typeof value, string>>;\n            return 'no';\n          });\n\n      expect(f(102)).toBe('yes 102');\n      expect(f()).toBe('yes undefined');\n      expect(f('gabriel')).toBe('no');\n    });\n\n    it(`P.number.select()`, () => {\n      const f = (input?: string | number) =>\n        match({ input })\n          .with({ input: P.number.select() }, (value) => {\n            type t = Expect<Equal<typeof value, number>>;\n            return `yes ${value}`;\n          })\n          .otherwise(() => 'no');\n\n      expect(f(102)).toBe('yes 102');\n      expect(f()).toBe('no');\n      expect(f('gabriel')).toBe('no');\n    });\n\n    it(`P.number.int().positive().finite().between(..).optional().select(),`, () => {\n      const f = (input?: string | number) =>\n        match({ input })\n          .with(\n            {\n              input: P.number\n                .int()\n                .positive()\n                .finite()\n                .between(3, 7)\n                .optional()\n                .select(),\n            },\n            (value) => {\n              type t = Expect<Equal<typeof value, number | undefined>>;\n              return `yes ${value}`;\n            }\n          )\n          .otherwise(() => 'no');\n\n      expect(f(5)).toBe('yes 5');\n      expect(f()).toBe('yes undefined');\n      expect(f(1)).toBe('no');\n      expect(f(8)).toBe('no');\n      expect(f(-2)).toBe('no');\n      expect(f(4.123)).toBe('no');\n      expect(f(Infinity)).toBe('no');\n    });\n  });\n\n  describe('bigint compositions', () => {\n    it(`P.bigint.optional()`, () => {\n      const f = (input?: string | bigint) =>\n        match(input)\n          .with(P.bigint.optional(), (value) => {\n            type t = Expect<Equal<typeof value, bigint | undefined>>;\n            return `yes ${value}`;\n          })\n          .otherwise((value) => {\n            type t = Expect<Equal<typeof value, string>>;\n            return 'no';\n          });\n\n      expect(f(102n)).toBe('yes 102');\n      expect(f()).toBe('yes undefined');\n      expect(f('gabriel')).toBe('no');\n    });\n\n    it(`P.bigint.select()`, () => {\n      const f = (input?: string | bigint) =>\n        match({ input })\n          .with({ input: P.bigint.select() }, (value) => {\n            type t = Expect<Equal<typeof value, bigint>>;\n            return `yes ${value}`;\n          })\n          .otherwise(() => 'no');\n\n      expect(f(102n)).toBe('yes 102');\n      expect(f()).toBe('no');\n      expect(f('gabriel')).toBe('no');\n    });\n\n    it(`P.bigint.positive().between(..).optional().select(),`, () => {\n      const f = (input?: string | bigint) =>\n        match({ input })\n          .with(\n            {\n              input: P.bigint.positive().between(3n, 7n).optional().select(),\n            },\n            (value) => {\n              type t = Expect<Equal<typeof value, bigint | undefined>>;\n              return `yes ${value}`;\n            }\n          )\n          .otherwise(() => 'no');\n\n      expect(f(5n)).toBe('yes 5');\n      expect(f()).toBe('yes undefined');\n      expect(f(1n)).toBe('no');\n      expect(f(8n)).toBe('no');\n      expect(f(-2n)).toBe('no');\n    });\n  });\n\n  describe('and', () => {\n    it('should infer the intersection of narrowed patterns', () => {\n      const f = (input?: string | number) =>\n        match(input)\n          .with(\n            P.string.startsWith('hello ').and(P.string.endsWith('!')),\n            (value) => {\n              type t = Expect<\n                Equal<typeof value, `hello ${string}` & `${string}!`>\n              >;\n              return `yes: ${value}`;\n            }\n          )\n          .otherwise(() => 'no');\n\n      expect(f('hello gabriel!')).toBe('yes: hello gabriel!');\n      expect(f('hello gabriel')).toBe('no');\n      expect(f('gabriel!')).toBe('no');\n      expect(f('gabriel')).toBe('no');\n    });\n  });\n\n  describe('or', () => {\n    it('should infer the union of narrowed patterns', () => {\n      const f = (input?: string | number) =>\n        match(input)\n          .with(\n            P.string.startsWith('hello ').or(P.string.endsWith('!')),\n            (value) => {\n              type t = Expect<\n                Equal<typeof value, `hello ${string}` | `${string}!`>\n              >;\n              return `yes: ${value}`;\n            }\n          )\n          .otherwise(() => 'no');\n\n      expect(f('hello gabriel!')).toBe('yes: hello gabriel!');\n      expect(f('hello gabriel')).toBe('yes: hello gabriel');\n      expect(f('gabriel!')).toBe('yes: gabriel!');\n      expect(f('gabriel')).toBe('no');\n    });\n  });\n});\n"
  },
  {
    "path": "tests/deep-exclude.test.ts",
    "content": "import { DeepExclude } from '../src/types/DeepExclude';\nimport {\n  DistributeMatchingUnions,\n  FindUnions,\n  FindUnionsMany,\n} from '../src/types/DistributeUnions';\nimport { Primitives, Equal, Expect } from '../src/types/helpers';\nimport { IsMatching } from '../src/types/IsMatching';\nimport { BigUnion, Option, State } from './types-catalog/utils';\n\ntype Colors = 'pink' | 'purple' | 'red' | 'yellow' | 'blue';\n\ndescribe('DeepExclude', () => {\n  it('Primitives', () => {\n    type cases = [\n      Expect<Equal<DeepExclude<string, 'hello'>, string>>,\n      Expect<Equal<DeepExclude<string, string>, never>>,\n      Expect<Equal<DeepExclude<string | number, string>, number>>,\n      Expect<Equal<DeepExclude<string | number, boolean>, string | number>>,\n      Expect<\n        Equal<\n          DeepExclude<Primitives, null | undefined>,\n          string | number | bigint | boolean | symbol\n        >\n      >,\n      Expect<Equal<DeepExclude<Primitives, never>, Primitives>>\n    ];\n  });\n\n  it('Literals', () => {\n    type cases = [\n      Expect<Equal<DeepExclude<'hello' | 'bonjour', 'hello'>, 'bonjour'>>,\n      Expect<\n        Equal<DeepExclude<'hello' | 'bonjour', 'hola'>, 'hello' | 'bonjour'>\n      >,\n      Expect<Equal<DeepExclude<1 | 2 | 3, 3>, 1 | 2>>,\n      Expect<Equal<DeepExclude<'hello' | 1, string>, 1>>,\n      Expect<Equal<DeepExclude<'hello' | 1, number>, 'hello'>>,\n      Expect<Equal<DeepExclude<200n | number, bigint>, number>>,\n      Expect<Equal<DeepExclude<undefined | number, number>, undefined>>\n    ];\n  });\n\n  describe('Objects', () => {\n    it('should correctly exclude when it matches', () => {\n      type cases = [\n        Expect<Equal<DeepExclude<{ a: 'x' | 'y' }, { a: string }>, never>>,\n        Expect<Equal<DeepExclude<{ a: 'x' | 'y' }, { a: 'x' }>, { a: 'y' }>>\n      ];\n    });\n\n    it(\"if it doesn't match, it should leave the data structure untouched\", () => {\n      type cases = [\n        Expect<\n          Equal<DeepExclude<{ a: 'x' | 'y' }, { b: 'x' }>, { a: 'x' | 'y' }>\n        >,\n        Expect<\n          Equal<DeepExclude<{ a: 'x' | 'y' }, { a: 'z' }>, { a: 'x' | 'y' }>\n        >\n      ];\n    });\n\n    it('should work with nested object and only distribute what is necessary', () => {\n      type x = DeepExclude<{ str: string | null | undefined }, { str: string }>;\n      type xx = DistributeMatchingUnions<\n        { str: string | null | undefined },\n        { str: string }\n      >;\n      type xxx = FindUnionsMany<\n        { str: string | null | undefined },\n        { str: string }\n      >;\n      type xxxx = IsMatching<\n        { str: string | null | undefined },\n        { str: string }\n      >;\n      type xxxxx = FindUnions<\n        { str: string | null | undefined },\n        { str: string },\n        []\n      >;\n      type y = DeepExclude<\n        { str: string | null | undefined },\n        { str: null | undefined }\n      >;\n\n      type cases = [\n        Expect<Equal<x, { str: null } | { str: undefined }>>,\n        Expect<Equal<y, { str: string }>>,\n        Expect<\n          Equal<\n            DeepExclude<{ a: { b: 'x' | 'y' } }, { a: { b: 'x' } }>,\n            { a: { b: 'y' } }\n          >\n        >,\n        Expect<\n          Equal<\n            DeepExclude<{ a: { b: 'x' | 'y' | 'z' } }, { a: { b: 'x' } }>,\n            { a: { b: 'y' } } | { a: { b: 'z' } }\n          >\n        >,\n        Expect<\n          Equal<\n            DeepExclude<\n              { a: { b: 'x' | 'y' | 'z' }; c: 'u' | 'v' },\n              { a: { b: 'x' } }\n            >,\n            { a: { b: 'y' }; c: 'u' | 'v' } | { a: { b: 'z' }; c: 'u' | 'v' }\n          >\n        >,\n        Expect<\n          Equal<\n            DeepExclude<\n              { a: { b: 'x' | 'y' | 'z' }; c: 'u' | 'v' },\n              { c: 'u' }\n            >,\n            { a: { b: 'x' | 'y' | 'z' }; c: 'v' }\n          >\n        >,\n        Expect<\n          Equal<\n            DeepExclude<\n              { a: { b: 'x' | 'y' | 'z' }; c: 'u' | 'v' },\n              { c: 'u' }\n            >,\n            { a: { b: 'x' | 'y' | 'z' }; c: 'v' }\n          >\n        >\n      ];\n    });\n\n    it(\"should exclude the undefined case of optional properties when the pattern's key is also optional\", () => {\n      type input = {\n        type: 'a';\n        data?: { type: 'img'; src: string } | { type: 'text'; p: string };\n      };\n      type pattern = {\n        readonly type: 'a';\n        readonly data?: { readonly type: 'img' };\n      };\n      type res1 = DeepExclude<input, pattern>;\n      type test1 = Expect<\n        Equal<res1, { type: 'a'; data: { type: 'text'; p: string } }>\n      >;\n    });\n  });\n\n  describe('Tuples', () => {\n    it('should correctly exclude when it matches', () => {\n      type cases = [\n        Expect<Equal<DeepExclude<['x' | 'y'], [string]>, never>>,\n        Expect<Equal<DeepExclude<['x' | 'y'], ['x']>, ['y']>>,\n        Expect<\n          Equal<\n            DeepExclude<[string, string], readonly [unknown, unknown]>,\n            never\n          >\n        >,\n        Expect<\n          Equal<\n            DeepExclude<[number, State], [unknown, { status: 'error' }]>,\n            | [number, { status: 'idle' }]\n            | [number, { status: 'loading' }]\n            | [number, { status: 'success'; data: string }]\n          >\n        >,\n        Expect<\n          Equal<\n            DeepExclude<\n              readonly [number, State],\n              [unknown, { status: 'error' }]\n            >,\n            | [number, { status: 'idle' }]\n            | [number, { status: 'loading' }]\n            | [number, { status: 'success'; data: string }]\n          >\n        >\n      ];\n    });\n\n    it(\"if it doesn't match, it should leave the data structure untouched\", () => {\n      type cases = [\n        Expect<Equal<DeepExclude<['x' | 'y'], ['z']>, ['x' | 'y']>>,\n        Expect<Equal<DeepExclude<['x' | 'y'], []>, ['x' | 'y']>>,\n        Expect<Equal<DeepExclude<['x' | 'y'], ['a', 'b', 'c']>, ['x' | 'y']>>\n      ];\n    });\n\n    it('should work with nested tuples and only distribute what is necessary', () => {\n      type cases = [\n        Expect<Equal<DeepExclude<[['x' | 'y']], [['x']]>, [['y']]>>,\n        Expect<\n          Equal<DeepExclude<[['x' | 'y' | 'z']], [['x']]>, [['y']] | [['z']]>\n        >,\n        Expect<\n          Equal<\n            DeepExclude<[['x' | 'y' | 'z'], 'u' | 'v'], [['x'], unknown]>,\n            [['y'], 'u' | 'v'] | [['z'], 'u' | 'v']\n          >\n        >,\n        Expect<\n          Equal<\n            DeepExclude<[['x' | 'y' | 'z'], 'u' | 'v'], [unknown, 'v']>,\n            [['x' | 'y' | 'z'], 'u']\n          >\n        >\n      ];\n    });\n\n    it('should work with nested unary tuples', () => {\n      type State = {};\n      type Msg = [type: 'Login'] | [type: 'UrlChange', url: string];\n      type Input = [State, Msg];\n\n      type cases = [\n        Expect<Equal<DeepExclude<[[number]], [[unknown]]>, never>>,\n        Expect<Equal<DeepExclude<[[[number]]], [[[unknown]]]>, never>>,\n        Expect<Equal<DeepExclude<[[[[number]]]], [[[[unknown]]]]>, never>>,\n        Expect<\n          Equal<\n            DeepExclude<[[[number]]], readonly [readonly [readonly [unknown]]]>,\n            never\n          >\n        >,\n        Expect<\n          Equal<\n            DeepExclude<\n              readonly [[[[{ t: number }]]]],\n              readonly [[[[{ t: unknown }]]]]\n            >,\n            never\n          >\n        >,\n        Expect<\n          Equal<\n            DeepExclude<[{}, Msg], [unknown, ['UrlChange', unknown]]>,\n            [{}, [type: 'Login']]\n          >\n        >\n      ];\n    });\n  });\n\n  describe('Variadic', () => {\n    it('should correctly turn variadic exclude into their opposite', () => {\n      type res1 = DeepExclude<number[], [number, ...number[]]>;\n      type test1 = Expect<Equal<res1, []>>;\n\n      type res2 = DeepExclude<number[], []>;\n      type test2 = Expect<Equal<res2, [number, ...number[]]>>;\n\n      type res3 = DeepExclude<number[], [...number[], number]>;\n      type test3 = Expect<Equal<res3, []>>;\n\n      type res4 = DeepExclude<[number, ...number[]], [...number[], number]>;\n      // @ts-expect-error fixme! never would make more sense here.\n      type test4 = Expect<Equal<res4, never>>;\n    });\n\n    it('should only exclude if the pattern really matches', () => {\n      type res1 = DeepExclude<number[], [string, ...number[]]>;\n      type test1 = Expect<Equal<res1, number[]>>;\n\n      type res3 = DeepExclude<number[], [...string[], number]>;\n      type test3 = Expect<Equal<res3, number[]>>;\n\n      // matches, but some cases may not have been handled.\n      type res4 = DeepExclude<[number, ...string[]], [...number[], string]>;\n      type test4 = Expect<Equal<res4, [number, ...string[]]>>;\n    });\n  });\n\n  describe('List', () => {\n    type cases = [\n      Expect<Equal<DeepExclude<(1 | 2 | 3)[], 1[]>, (1 | 2 | 3)[]>>,\n      Expect<Equal<DeepExclude<(1 | 2 | 3)[], (1 | 2 | 3)[]>, never>>,\n      Expect<Equal<DeepExclude<(1 | 2 | 3)[], unknown[]>, never>>,\n      Expect<\n        Equal<DeepExclude<(1 | 2 | 3)[] | string[], string[]>, (1 | 2 | 3)[]>\n      >\n    ];\n\n    it('should work with empty list patterns', () => {\n      type res1 = DeepExclude<{ values: (1 | 2 | 3)[] }, { values: [] }>;\n      type test1 = Expect<\n        Equal<res1, { values: [1 | 2 | 3, ...(1 | 2 | 3)[]] }>\n      >;\n\n      type cases = [\n        Expect<Equal<DeepExclude<[] | [1, 2, 3], []>, [1, 2, 3]>>,\n        Expect<\n          Equal<\n            DeepExclude<{ values: [] | [1, 2, 3] }, { values: [] }>,\n            { values: [1, 2, 3] }\n          >\n        >,\n        Expect<\n          Equal<\n            DeepExclude<{ values: [1, 2, 3] }, { values: [] }>,\n            { values: [1, 2, 3] }\n          >\n        >\n      ];\n    });\n  });\n\n  describe('Sets', () => {\n    type cases = [\n      Expect<Equal<DeepExclude<Set<1 | 2 | 3>, Set<1>>, Set<1 | 2 | 3>>>,\n      Expect<Equal<DeepExclude<Set<1 | 2 | 3>, Set<1 | 2 | 3>>, never>>,\n      Expect<Equal<DeepExclude<Set<1 | 2 | 3>, Set<unknown>>, never>>,\n      Expect<\n        Equal<\n          DeepExclude<Set<1 | 2 | 3> | Set<string>, Set<string>>,\n          Set<1 | 2 | 3>\n        >\n      >\n    ];\n  });\n\n  describe('Maps', () => {\n    type cases = [\n      Expect<\n        Equal<\n          DeepExclude<Map<string, 1 | 2 | 3>, Map<string, 1>>,\n          Map<string, 1 | 2 | 3>\n        >\n      >,\n      Expect<\n        Equal<\n          DeepExclude<Map<string, 1 | 2 | 3>, Map<string, 1 | 2 | 3>>,\n          never\n        >\n      >,\n      Expect<\n        Equal<DeepExclude<Map<string, 1 | 2 | 3>, Map<string, unknown>>, never>\n      >,\n      Expect<\n        Equal<\n          DeepExclude<\n            Map<string, 1 | 2 | 3> | Map<string, string>,\n            Map<string, string>\n          >,\n          Map<string, 1 | 2 | 3>\n        >\n      >\n    ];\n  });\n\n  it('should work with big unions', () => {\n    type cases = [\n      Expect<\n        Equal<\n          DeepExclude<\n            | { type: 'textWithColor'; union: BigUnion }\n            | {\n                type: 'textWithColorAndBackground';\n                union: BigUnion;\n                union2: BigUnion;\n              },\n            { type: 'textWithColor' }\n          >,\n          {\n            type: 'textWithColorAndBackground';\n            union: BigUnion;\n            union2: BigUnion;\n          }\n        >\n      >,\n      Expect<\n        Equal<\n          DeepExclude<\n            | { type: 'textWithColor'; union: BigUnion }\n            | {\n                type: 'textWithColorAndBackground';\n                union: BigUnion;\n                union2: BigUnion;\n              },\n            {\n              type: 'textWithColorAndBackground';\n              union: Exclude<BigUnion, 'a'>;\n            }\n          >,\n          | { type: 'textWithColor'; union: BigUnion }\n          | {\n              type: 'textWithColorAndBackground';\n              union: 'a';\n              union2: BigUnion;\n            }\n        >\n      >\n    ];\n  });\n\n  it('should work in common cases', () => {\n    type cases = [\n      Expect<Equal<DeepExclude<'a' | 'b' | 'c', 'a'>, 'b' | 'c'>>,\n      Expect<\n        Equal<\n          DeepExclude<\n            | { type: 'textWithColor'; color: Colors }\n            | {\n                type: 'textWithColorAndBackground';\n                color: Colors;\n                backgroundColor: Colors;\n              },\n            { type: 'textWithColor' }\n          >,\n          {\n            type: 'textWithColorAndBackground';\n            color: Colors;\n            backgroundColor: Colors;\n          }\n        >\n      >,\n      Expect<\n        Equal<\n          DeepExclude<\n            | { type: 'textWithColor'; color: Colors }\n            | {\n                type: 'textWithColorAndBackground';\n                color: Colors;\n                backgroundColor: Colors;\n              },\n            { type: 'textWithColor'; color: 'pink' }\n          >,\n          | {\n              type: 'textWithColorAndBackground';\n              color: Colors;\n              backgroundColor: Colors;\n            }\n          | { type: 'textWithColor'; color: 'purple' }\n          | { type: 'textWithColor'; color: 'red' }\n          | { type: 'textWithColor'; color: 'yellow' }\n          | { type: 'textWithColor'; color: 'blue' }\n        >\n      >,\n      Expect<\n        Equal<\n          DeepExclude<\n            [Option<{ type: 'a' } | { type: 'b' }>, 'c' | 'd'],\n            [{ kind: 'some'; value: { type: 'a' } }, any]\n          >,\n          | [{ kind: 'none' }, 'c' | 'd']\n          | [{ kind: 'some'; value: { type: 'b' } }, 'c' | 'd']\n        >\n      >,\n      Expect<\n        Equal<\n          DeepExclude<\n            { x: 'a' | 'b'; y: 'c' | 'd'; z: 'e' | 'f' },\n            { x: 'a'; y: 'c' }\n          >,\n          | { x: 'b'; y: 'c'; z: 'e' | 'f' }\n          | { x: 'b'; y: 'd'; z: 'e' | 'f' }\n          | { x: 'a'; y: 'd'; z: 'e' | 'f' }\n        >\n      >\n    ];\n  });\n\n  describe('Multiple patterns', () => {\n    it('should work when pattern is a union', () => {\n      type cases = [\n        Expect<\n          Equal<\n            DeepExclude<\n              { x: 'a' | 'b'; y: 'c' | 'd'; z: 'e' | 'f' },\n              { x: 'a'; y: 'c' } | { x: 'b'; y: 'c' }\n            >,\n            { x: 'b'; y: 'd'; z: 'e' | 'f' } | { x: 'a'; y: 'd'; z: 'e' | 'f' }\n          >\n        >,\n        Expect<\n          Equal<\n            DeepExclude<\n              { a: { b: 'x' | 'y' | 'z' }; c: 'u' | 'v' },\n              { c: 'u' } | { a: { b: 'x' } }\n            >,\n            { a: { b: 'y' }; c: 'v' } | { a: { b: 'z' }; c: 'v' }\n          >\n        >\n      ];\n    });\n  });\n\n  describe('Excluding nested unions', () => {\n    it('should correctly exclude', () => {\n      type cases = [\n        Expect<\n          Equal<\n            DeepExclude<\n              ['a' | 'b' | 'c', 'a' | 'b' | 'c'],\n              ['b' | 'c', 'b' | 'c']\n            >,\n            ['a', 'a'] | ['a', 'b'] | ['a', 'c'] | ['b', 'a'] | ['c', 'a']\n          >\n        >,\n        Expect<\n          Equal<\n            DeepExclude<\n              ['a' | 'b' | 'c', { type: 'a' | 'b' | 'c' }],\n              ['b' | 'c', { type: 'c' }]\n            >,\n            | ['a', { type: 'c' }]\n            | ['a', { type: 'a' }]\n            | ['a', { type: 'b' }]\n            | ['b', { type: 'a' }]\n            | ['b', { type: 'b' }]\n            | ['c', { type: 'a' }]\n            | ['c', { type: 'b' }]\n          >\n        >,\n        Expect<\n          Equal<\n            DeepExclude<\n              ['a' | 'b' | 'c', { type: 'a' | 'b' | 'c' }],\n              ['b' | 'c', { type: 'b' | 'c' }]\n            >,\n            | ['a', { type: 'a' }]\n            | ['a', { type: 'b' }]\n            | ['a', { type: 'c' }]\n            | ['b', { type: 'a' }]\n            | ['c', { type: 'a' }]\n          >\n        >,\n        Expect<\n          Equal<\n            DeepExclude<\n              ['a' | 'b' | 'c', { type: 'a' | 'b' | 'c' | 'd' }],\n              ['b' | 'c', { type: 'b' | 'c' }]\n            >,\n            | ['a', { type: 'a' }]\n            | ['a', { type: 'b' }]\n            | ['a', { type: 'c' }]\n            | ['a', { type: 'd' }]\n            | ['b', { type: 'a' }]\n            | ['b', { type: 'd' }]\n            | ['c', { type: 'a' }]\n            | ['c', { type: 'd' }]\n          >\n        >\n      ];\n    });\n  });\n\n  describe('readonly', () => {\n    type Input = readonly ['a' | 'b', 'c' | 'd'];\n    type p = ['a', 'c'] | ['a', 'd'] | ['b', 'c'] | ['b', 'd'];\n\n    type cases = [\n      Expect<\n        Equal<\n          DeepExclude<Input, ['a', 'c']>,\n          ['a', 'd'] | ['b', 'c'] | ['b', 'd']\n        >\n      >,\n      Expect<Equal<DeepExclude<Input, p>, never>>\n    ];\n  });\n\n  it('should work with unknown', () => {\n    type cases = [\n      Expect<\n        Equal<\n          DeepExclude<\n            [number, { type: 'a'; b: string }],\n            [unknown, { type: 'a'; b: unknown }]\n          >,\n          never\n        >\n      >\n    ];\n  });\n\n  it('should work when `b` contains a union', () => {\n    type t = Expect<\n      Equal<\n        DeepExclude<\n          {\n            type: 'c';\n            value:\n              | { type: 'd'; value: boolean }\n              | { type: 'e'; value: string[] }\n              | { type: 'f'; value: number[] };\n          },\n          {\n            type: 'c';\n            value: {\n              type: 'd' | 'e';\n            };\n          }\n        >,\n        { type: 'c'; value: { type: 'f'; value: number[] } }\n      >\n    >;\n  });\n});\n"
  },
  {
    "path": "tests/distribute-unions.test.ts",
    "content": "import {\n  FindUnions,\n  Distribute,\n  DistributeMatchingUnions,\n  FindUnionsMany,\n} from '../src/types/DistributeUnions';\n\nimport { Equal, Expect } from '../src/types/helpers';\nimport { Option } from './types-catalog/utils';\n\ndescribe('FindAllUnions', () => {\n  it('should correctly find all unions on an object', () => {\n    type res1 = FindUnions<{ a: 1 | 2; b: 3 | 4; c: 6 | 7 }, { a: 1; b: 3 }>;\n    type test1 = Expect<\n      Equal<\n        res1,\n        [\n          {\n            cases:\n              | {\n                  value: 1;\n                  subUnions: [];\n                }\n              | {\n                  value: 2;\n                  subUnions: [];\n                };\n            path: ['a'];\n          },\n          {\n            cases:\n              | {\n                  value: 4;\n                  subUnions: [];\n                }\n              | {\n                  value: 3;\n                  subUnions: [];\n                };\n            path: ['b'];\n          }\n        ]\n      >\n    >;\n    type res2 = FindUnions<\n      {\n        a: 1 | 2;\n        b: 3 | 4;\n        c: 5 | 6;\n        d: 7 | 8; // not matched\n      },\n      { a: 1; b: 3; c: 5 }\n    >;\n    type test2 = Expect<\n      Equal<\n        res2,\n        [\n          {\n            cases:\n              | {\n                  value: 1;\n                  subUnions: [];\n                }\n              | {\n                  value: 2;\n                  subUnions: [];\n                };\n            path: ['a'];\n          },\n          {\n            cases:\n              | {\n                  value: 3;\n                  subUnions: [];\n                }\n              | {\n                  value: 4;\n                  subUnions: [];\n                };\n            path: ['b'];\n          },\n          {\n            cases:\n              | {\n                  value: 5;\n                  subUnions: [];\n                }\n              | {\n                  value: 6;\n                  subUnions: [];\n                };\n            path: ['c'];\n          }\n        ]\n      >\n    >;\n    type res3 = FindUnions<\n      {\n        a: 1 | 2;\n        b: 3 | 4;\n        c: 5 | 6;\n        d: { e: 7 | 8; f: 9 | 10 };\n        g: 11 | 12; // not matched by the pattern\n      },\n      {\n        a: 1;\n        b: 3;\n        c: 5;\n        d: { e: 7; f: 9 };\n      }\n    >;\n\n    type test3 = Expect<\n      Equal<\n        res3,\n        [\n          {\n            cases:\n              | {\n                  value: 1;\n                  subUnions: [];\n                }\n              | {\n                  value: 2;\n                  subUnions: [];\n                };\n            path: ['a'];\n          },\n          {\n            cases:\n              | {\n                  value: 3;\n                  subUnions: [];\n                }\n              | {\n                  value: 4;\n                  subUnions: [];\n                };\n            path: ['b'];\n          },\n          {\n            cases:\n              | {\n                  value: 5;\n                  subUnions: [];\n                }\n              | {\n                  value: 6;\n                  subUnions: [];\n                };\n            path: ['c'];\n          },\n          {\n            cases:\n              | {\n                  value: 7;\n                  subUnions: [];\n                }\n              | {\n                  value: 8;\n                  subUnions: [];\n                };\n            path: ['d', 'e'];\n          },\n          {\n            cases:\n              | {\n                  value: 9;\n                  subUnions: [];\n                }\n              | {\n                  value: 10;\n                  subUnions: [];\n                };\n            path: ['d', 'f'];\n          }\n        ]\n      >\n    >;\n\n    type res4 = FindUnions<\n      { a: { b: { e: 7 | 8; f: 9 | 10 } } } | { c: 11 | 12 },\n      { a: { b: { e: 7; f: 9 } } }\n    >;\n    type test4 = Expect<\n      Equal<\n        res4,\n        [\n          {\n            cases:\n              | {\n                  value: { a: { b: { e: 7 | 8; f: 9 | 10 } } };\n                  subUnions: [\n                    {\n                      cases:\n                        | {\n                            value: 7;\n                            subUnions: [];\n                          }\n                        | {\n                            value: 8;\n                            subUnions: [];\n                          };\n                      path: ['a', 'b', 'e'];\n                    },\n                    {\n                      cases:\n                        | {\n                            value: 9;\n                            subUnions: [];\n                          }\n                        | {\n                            value: 10;\n                            subUnions: [];\n                          };\n                      path: ['a', 'b', 'f'];\n                    }\n                  ];\n                }\n              | { value: { c: 11 | 12 }; subUnions: [] };\n            path: [];\n          }\n        ]\n      >\n    >;\n\n    type res5 = FindUnions<\n      {\n        e: 'not a union';\n        a: {\n          e: 7 | 8;\n          f: 9 | 10;\n          g: 11 | 12; // not matched\n        };\n        b: 2 | 3;\n      },\n      { e: 'not a union'; a: { e: 7; f: 9 }; b: 2 }\n    >;\n    type test5 = Expect<\n      Equal<\n        res5,\n        [\n          {\n            cases:\n              | {\n                  value: 7;\n                  subUnions: [];\n                }\n              | {\n                  value: 8;\n                  subUnions: [];\n                };\n            path: ['a', 'e'];\n          },\n          {\n            cases:\n              | {\n                  value: 9;\n                  subUnions: [];\n                }\n              | {\n                  value: 10;\n                  subUnions: [];\n                };\n            path: ['a', 'f'];\n          },\n          {\n            cases:\n              | {\n                  value: 2;\n                  subUnions: [];\n                }\n              | {\n                  value: 3;\n                  subUnions: [];\n                };\n            path: ['b'];\n          }\n        ]\n      >\n    >;\n  });\n\n  it('should correctly find all unions on a tuple', () => {\n    type cases = [\n      Expect<\n        Equal<\n          FindUnions<[1 | 2, 3 | 4], [1, 3]>,\n          [\n            {\n              cases:\n                | {\n                    value: 1;\n                    subUnions: [];\n                  }\n                | {\n                    value: 2;\n                    subUnions: [];\n                  };\n              path: [0];\n            },\n            {\n              cases:\n                | {\n                    value: 3;\n                    subUnions: [];\n                  }\n                | {\n                    value: 4;\n                    subUnions: [];\n                  };\n              path: [1];\n            }\n          ]\n        >\n      >,\n      Expect<\n        Equal<\n          FindUnions<[1 | 2, 3 | 4, 5 | 6], [1, 3, 5]>,\n          [\n            {\n              cases:\n                | {\n                    value: 1;\n                    subUnions: [];\n                  }\n                | {\n                    value: 2;\n                    subUnions: [];\n                  };\n              path: [0];\n            },\n            {\n              cases:\n                | {\n                    value: 3;\n                    subUnions: [];\n                  }\n                | {\n                    value: 4;\n                    subUnions: [];\n                  };\n              path: [1];\n            },\n            {\n              cases:\n                | {\n                    value: 5;\n                    subUnions: [];\n                  }\n                | {\n                    value: 6;\n                    subUnions: [];\n                  };\n              path: [2];\n            }\n          ]\n        >\n      >,\n      Expect<\n        Equal<\n          FindUnions<\n            { type: 'a'; value: 1 | 2 } | { type: 'b'; value: 4 | 5 },\n            { type: 'a'; value: 1 }\n          >,\n          [\n            {\n              cases:\n                | {\n                    value: { type: 'a'; value: 1 | 2 };\n                    subUnions: [\n                      {\n                        cases:\n                          | {\n                              value: 1;\n                              subUnions: [];\n                            }\n                          | {\n                              value: 2;\n                              subUnions: [];\n                            };\n                        path: ['value'];\n                      }\n                    ];\n                  }\n                | {\n                    value: { type: 'b'; value: 4 | 5 };\n                    subUnions: [];\n                  };\n              path: [];\n            }\n          ]\n        >\n      >,\n      Expect<\n        Equal<\n          FindUnions<readonly ['a' | 'b', 'c' | 'd'], ['a', 'c']>,\n          [\n            {\n              cases:\n                | {\n                    value: 'a';\n                    subUnions: [];\n                  }\n                | {\n                    value: 'b';\n                    subUnions: [];\n                  };\n              path: [0];\n            },\n            {\n              cases:\n                | {\n                    value: 'c';\n                    subUnions: [];\n                  }\n                | {\n                    value: 'd';\n                    subUnions: [];\n                  };\n              path: [1];\n            }\n          ]\n        >\n      >\n    ];\n  });\n\n  it('when matched against an empty array, the input should be turned into a union of empty array and non-empty array', () => {\n    type res1 = FindUnions<readonly number[], readonly []>;\n    type tes1 = Expect<\n      Equal<\n        res1,\n        [\n          {\n            cases:\n              | {\n                  value: readonly [];\n                  subUnions: [];\n                }\n              | {\n                  value: readonly [number, ...(readonly number[])];\n                  subUnions: [];\n                };\n            path: [];\n          }\n        ]\n      >\n    >;\n\n    type res2 = FindUnions<[number], []>;\n    type tes2 = Expect<Equal<res2, []>>;\n\n    type res3 = FindUnions<[number], [number, ...number[]]>;\n    type tes3 = Expect<Equal<res3, []>>;\n\n    type res4 = FindUnions<[number], [...number[], number]>;\n    type tes4 = Expect<Equal<res4, []>>;\n\n    type res5 = FindUnions<[number], [...number[], number]>;\n    type tes5 = Expect<Equal<res5, []>>;\n\n    type res6 = FindUnions<readonly number[], readonly [number, ...number[]]>;\n    type tes6 = Expect<\n      Equal<\n        res6,\n        [\n          {\n            cases:\n              | {\n                  value: readonly [];\n                  subUnions: [];\n                }\n              | {\n                  value: readonly [number, ...(readonly number[])];\n                  subUnions: [];\n                };\n            path: [];\n          }\n        ]\n      >\n    >;\n\n    type res7 = FindUnions<readonly number[], readonly [...number[], number]>;\n    type tes7 = Expect<\n      Equal<\n        res7,\n        [\n          {\n            cases:\n              | {\n                  value: readonly [];\n                  subUnions: [];\n                }\n              | {\n                  value: readonly [...number[], number];\n                  subUnions: [];\n                };\n            path: [];\n          }\n        ]\n      >\n    >;\n\n    type res8 = FindUnions<\n      readonly [...number[], number],\n      readonly [...number[], number]\n    >;\n    type tes8 = Expect<Equal<res8, []>>;\n\n    type res9 = FindUnions<\n      readonly [number, ...number[]],\n      readonly [number, ...number[]]\n    >;\n    type tes9 = Expect<Equal<res9, []>>;\n  });\n\n  it('should avoid duplicating the unions, even if the pattern matches the same path twice', () => {\n    type cases = [\n      Expect<\n        Equal<\n          FindUnionsMany<\n            { type: { x: 'a'; y: 1 | 2 } | { x: 'b'; y: 3 | 4 } },\n            { type: { x: 'a'; y: 1 } } | { type: { x: 'a'; y: 2 } }\n          >,\n          [\n            {\n              cases:\n                | {\n                    value: {\n                      x: 'a';\n                      y: 1 | 2;\n                    };\n                    subUnions: [\n                      {\n                        cases:\n                          | {\n                              value: 1;\n                              subUnions: [];\n                            }\n                          | {\n                              value: 2;\n                              subUnions: [];\n                            };\n                        path: ['type', 'y'];\n                      }\n                    ];\n                  }\n                | {\n                    value: {\n                      x: 'b';\n                      y: 3 | 4;\n                    };\n                    subUnions: [];\n                  };\n              path: ['type'];\n            }\n          ]\n        >\n      >\n    ];\n  });\n});\n\ndescribe('Distribute', () => {\n  it('should distribute unions into a list of values with their path', () => {\n    type cases = [\n      Expect<\n        Equal<\n          Distribute<\n            [\n              {\n                cases:\n                  | {\n                      value: 1;\n                      subUnions: [];\n                    }\n                  | {\n                      value: 2;\n                      subUnions: [];\n                    };\n                path: [0];\n              },\n              {\n                cases:\n                  | {\n                      value: 3;\n                      subUnions: [];\n                    }\n                  | {\n                      value: 4;\n                      subUnions: [];\n                    };\n                path: [1];\n              }\n            ]\n          >,\n          | [[1, [0]], [3, [1]]]\n          | [[1, [0]], [4, [1]]]\n          | [[2, [0]], [3, [1]]]\n          | [[2, [0]], [4, [1]]]\n        >\n      >,\n      Expect<\n        Equal<\n          Distribute<\n            [\n              {\n                cases:\n                  | {\n                      value: 1;\n                      subUnions: [];\n                    }\n                  | {\n                      value: 2;\n                      subUnions: [];\n                    };\n                path: [0];\n              },\n              {\n                cases:\n                  | {\n                      value: 3;\n                      subUnions: [];\n                    }\n                  | {\n                      value: 4;\n                      subUnions: [];\n                    };\n                path: [1];\n              },\n              {\n                cases:\n                  | {\n                      value: 5;\n                      subUnions: [];\n                    }\n                  | {\n                      value: 6;\n                      subUnions: [];\n                    };\n                path: [2];\n              }\n            ]\n          >,\n          | [[1, [0]], [3, [1]], [5, [2]]]\n          | [[1, [0]], [3, [1]], [6, [2]]]\n          | [[1, [0]], [4, [1]], [5, [2]]]\n          | [[1, [0]], [4, [1]], [6, [2]]]\n          | [[2, [0]], [3, [1]], [5, [2]]]\n          | [[2, [0]], [3, [1]], [6, [2]]]\n          | [[2, [0]], [4, [1]], [5, [2]]]\n          | [[2, [0]], [4, [1]], [6, [2]]]\n        >\n      >,\n      Equal<\n        // Nested\n        Distribute<\n          [\n            {\n              cases:\n                | {\n                    value: {\n                      type: 'a';\n                      value: 1 | 2;\n                    };\n                    subUnions: [\n                      {\n                        cases:\n                          | {\n                              value: 1;\n                              subUnions: [];\n                            }\n                          | {\n                              value: 2;\n                              subUnions: [];\n                            };\n                        path: ['value'];\n                      }\n                    ];\n                  }\n                | {\n                    value: {\n                      type: 'b';\n                      value: 4 | 5;\n                    };\n                    subUnions: [\n                      {\n                        cases:\n                          | {\n                              value: 4;\n                              subUnions: [];\n                            }\n                          | {\n                              value: 5;\n                              subUnions: [];\n                            };\n                        path: ['value'];\n                      }\n                    ];\n                  };\n              path: [];\n            }\n          ]\n        >,\n        | [[{ type: 'a'; value: 1 | 2 }, []], [1, ['value']]]\n        | [[{ type: 'a'; value: 1 | 2 }, []], [2, ['value']]]\n        | [[{ type: 'b'; value: 4 | 5 }, []], [4, ['value']]]\n        | [[{ type: 'b'; value: 4 | 5 }, []], [5, ['value']]]\n      >\n    ];\n  });\n});\n\ndescribe('DistributeMatchingUnions', () => {\n  type cases = [\n    Expect<\n      Equal<\n        DistributeMatchingUnions<\n          { a: 1 | 2; b: '3' | '4'; c: '5' | '6' },\n          { a: 1; b: '3'; c: '5' }\n        >,\n        | { a: 1; b: '3'; c: '5' }\n        | { a: 1; b: '3'; c: '6' }\n        | { a: 1; b: '4'; c: '5' }\n        | { a: 1; b: '4'; c: '6' }\n        | { a: 2; b: '3'; c: '5' }\n        | { a: 2; b: '3'; c: '6' }\n        | { a: 2; b: '4'; c: '5' }\n        | { a: 2; b: '4'; c: '6' }\n      >\n    >,\n    Expect<\n      Equal<\n        DistributeMatchingUnions<\n          { x: 'a'; value: Option<string> } | { x: 'b'; value: Option<number> },\n          { x: 'a'; value: { kind: 'none' } }\n        >,\n        | { x: 'a'; value: { kind: 'none' } }\n        | { x: 'a'; value: { kind: 'some'; value: string } }\n        | { x: 'b'; value: Option<number> }\n      >\n    >,\n    Expect<\n      Equal<\n        DistributeMatchingUnions<\n          [1, number] | ['two', string] | [3, boolean],\n          [3, true]\n        >,\n        [1, number] | ['two', string] | [3, false] | [3, true]\n      >\n    >\n  ];\n\n  it('should leave unions of literals untouched', () => {\n    type cases = [\n      Expect<Equal<DistributeMatchingUnions<'a' | 'b', 'a'>, 'a' | 'b'>>,\n      Expect<Equal<DistributeMatchingUnions<1 | 2, 1>, 1 | 2>>,\n      Expect<Equal<DistributeMatchingUnions<boolean, true>, false | true>>\n    ];\n  });\n\n  it('should work on nested tuples', () => {\n    type cases = [\n      Expect<\n        Equal<\n          DistributeMatchingUnions<\n            [1, ['two', Option<string>] | [3, Option<boolean>]],\n            [1, ['two', { kind: 'some'; value: string }]]\n          >,\n          | [1, ['two', { kind: 'none' }]]\n          | [1, ['two', { kind: 'some'; value: string }]]\n          | [1, [3, Option<boolean>]]\n        >\n      >,\n      Expect<\n        Equal<\n          DistributeMatchingUnions<\n            [1, ['two', Option<string>]] | [3, Option<boolean>],\n            [1, ['two', { kind: 'some'; value: string }]]\n          >,\n          | [1, ['two', { kind: 'none' }]]\n          | [1, ['two', { kind: 'some'; value: string }]]\n          | [3, Option<boolean>]\n        >\n      >,\n      Expect<\n        Equal<\n          DistributeMatchingUnions<['a' | 'b', 1 | 2], ['a', unknown]>,\n          ['a', 1 | 2] | ['b', 1 | 2]\n        >\n      >\n    ];\n  });\n\n  it(\"unknown should match but shouldn't distribute\", () => {\n    type cases = [\n      Expect<\n        Equal<\n          DistributeMatchingUnions<\n            [1, ['two', Option<string>]] | [3, Option<boolean>],\n            [1, unknown]\n          >,\n          [1, ['two', Option<string>]] | [3, Option<boolean>]\n        >\n      >,\n      Expect<\n        Equal<\n          DistributeMatchingUnions<\n            { a: 1 | 2; b: '3' | '4'; c: '5' | '6' },\n            { a: 1; b: unknown; c: unknown }\n          >,\n          | { a: 1; b: '3' | '4'; c: '5' | '6' }\n          | { a: 2; b: '3' | '4'; c: '5' | '6' }\n        >\n      >,\n      Expect<\n        Equal<\n          DistributeMatchingUnions<\n            { a: 1 | 2; b: '3' | '4'; c: '5' | '6' },\n            { a: 1; b: '3'; c: unknown }\n          >,\n          | { a: 1; b: '3'; c: '5' | '6' }\n          | { a: 2; b: '3'; c: '5' | '6' }\n          | { a: 1; b: '4'; c: '5' | '6' }\n          | { a: 2; b: '4'; c: '5' | '6' }\n        >\n      >,\n      Expect<\n        Equal<\n          DistributeMatchingUnions<\n            { a: 1 | 2; b: ['3' | '4', '5' | '6'] },\n            { a: 1; b: ['3', unknown] }\n          >,\n          | { a: 1; b: ['3', '5' | '6'] }\n          | { a: 2; b: ['3', '5' | '6'] }\n          | { a: 1; b: ['4', '5' | '6'] }\n          | { a: 2; b: ['4', '5' | '6'] }\n        >\n      >\n    ];\n  });\n\n  it('should work for non unions', () => {\n    type res1 = DistributeMatchingUnions<[], []>;\n    type test1 = Expect<Equal<res1, []>>;\n\n    type cases = [\n      Expect<Equal<DistributeMatchingUnions<{}, {}>, {}>>,\n      Expect<\n        Equal<\n          DistributeMatchingUnions<Map<string, string>, Map<string, string>>,\n          Map<string, string>\n        >\n      >,\n      Expect<\n        Equal<DistributeMatchingUnions<Set<string>, Set<string>>, Set<string>>\n      >,\n      Expect<Equal<DistributeMatchingUnions<string, string>, string>>,\n      Expect<Equal<DistributeMatchingUnions<number, number>, number>>,\n      Expect<Equal<DistributeMatchingUnions<any, any>, any>>,\n      Expect<Equal<DistributeMatchingUnions<never, never>, never>>,\n      Expect<Equal<DistributeMatchingUnions<unknown, unknown>, unknown>>\n    ];\n  });\n\n  it('should work with objects', () => {\n    type X = 1 | 2 | 3 | 4 | 5 | 6 | 7;\n\n    type cases = [\n      Expect<\n        Equal<\n          DistributeMatchingUnions<\n            { a: X; b: X; c: X; d: X; e: X; f: X; g: X; h: X; i: X },\n            { a: 1 }\n          >,\n          | { a: 1; b: X; c: X; d: X; e: X; f: X; g: X; h: X; i: X }\n          | { a: 2; b: X; c: X; d: X; e: X; f: X; g: X; h: X; i: X }\n          | { a: 3; b: X; c: X; d: X; e: X; f: X; g: X; h: X; i: X }\n          | { a: 4; b: X; c: X; d: X; e: X; f: X; g: X; h: X; i: X }\n          | { a: 5; b: X; c: X; d: X; e: X; f: X; g: X; h: X; i: X }\n          | { a: 6; b: X; c: X; d: X; e: X; f: X; g: X; h: X; i: X }\n          | { a: 7; b: X; c: X; d: X; e: X; f: X; g: X; h: X; i: X }\n        >\n      >,\n      Expect<\n        Equal<\n          DistributeMatchingUnions<\n            {\n              type: 'type';\n              x: undefined;\n              q: string;\n              union1: 'a' | 'b';\n              color: '3';\n              union2: '1' | '2';\n            },\n            { union1: 'a'; union2: '1' }\n          >,\n          | {\n              type: 'type';\n              q: string;\n              x: undefined;\n              union1: 'a';\n              color: '3';\n              union2: '1';\n            }\n          | {\n              type: 'type';\n              q: string;\n              x: undefined;\n              union1: 'a';\n              color: '3';\n              union2: '2';\n            }\n          | {\n              type: 'type';\n              q: string;\n              x: undefined;\n              union1: 'b';\n              color: '3';\n              union2: '1';\n            }\n          | {\n              type: 'type';\n              q: string;\n              x: undefined;\n              union1: 'b';\n              color: '3';\n              union2: '2';\n            }\n        >\n      >\n    ];\n  });\n\n  it('should not distribute unions for lists, set and maps', () => {\n    // The reason is that list can be heterogeneous, so\n    // matching on a A[] for a in input of (A|B)[] doesn't\n    // rule anything out. You can still have a (A|B)[] afterward.\n    // The same logic goes for Set and Maps.\n    type cases = [\n      Expect<\n        Equal<DistributeMatchingUnions<('a' | 'b')[], 'a'[]>, ('a' | 'b')[]>\n      >,\n      Expect<\n        Equal<\n          DistributeMatchingUnions<\n            { type: 'a' | 'b'; x: 'c' | 'd' }[],\n            { type: 'a'; x: 'c' }[]\n          >,\n          { type: 'a' | 'b'; x: 'c' | 'd' }[]\n        >\n      >,\n      Expect<\n        Equal<\n          DistributeMatchingUnions<Set<'a' | 'b'>, Set<'a'>>,\n          Set<'a' | 'b'>\n        >\n      >,\n      Expect<\n        Equal<\n          DistributeMatchingUnions<Map<string, 'a' | 'b'>, Map<string, 'a'>>,\n          Map<string, 'a' | 'b'>\n        >\n      >,\n      Expect<\n        Equal<\n          DistributeMatchingUnions<\n            | {\n                type: 'a';\n                items: ({ t: 'x'; some: string; data: number } | { t: 'y' })[];\n              }\n            | {\n                type: 'b';\n                items: { other: boolean; data: string }[];\n              },\n            { type: 'a'; items: { t: 'y' }[] }\n          >,\n          | {\n              type: 'a';\n              items: ({ t: 'x'; some: string; data: number } | { t: 'y' })[];\n            }\n          | {\n              type: 'b';\n              items: { other: boolean; data: string }[];\n            }\n        >\n      >\n    ];\n  });\n\n  it('should return the input if the inverted pattern is `unknown` (if the pattern is `P._`', () => {\n    type cases = [\n      Expect<\n        Equal<\n          DistributeMatchingUnions<\n            [1, number] | ['two', string] | [3, boolean],\n            unknown\n          >,\n          [1, number] | ['two', string] | [3, boolean]\n        >\n      >,\n      Expect<\n        Equal<\n          DistributeMatchingUnions<\n            { a: 1 | 2; b: '3' | '4'; c: '5' | '6' },\n            unknown\n          >,\n          { a: 1 | 2; b: '3' | '4'; c: '5' | '6' }\n        >\n      >,\n      Expect<\n        Equal<\n          DistributeMatchingUnions<\n            | { x: 'a'; value: Option<string> }\n            | { x: 'b'; value: Option<number> },\n            unknown\n          >,\n          { x: 'a'; value: Option<string> } | { x: 'b'; value: Option<number> }\n        >\n      >\n    ];\n  });\n\n  it('should work with readonly inputs', () => {\n    type cases = [\n      Expect<\n        Equal<\n          DistributeMatchingUnions<readonly ['a' | 'b', 'c' | 'd'], ['a', 'c']>,\n          ['a', 'c'] | ['a', 'd'] | ['b', 'c'] | ['b', 'd']\n        >\n      >\n    ];\n  });\n});\n"
  },
  {
    "path": "tests/exhaustive-fallback.test.ts",
    "content": "import { match, P } from '../src';\nimport { Equal, Expect } from '../src/types/helpers';\n\ndescribe('Exhaustive fallback function', () => {\n  it(\"should be called if the runtime value isn't expected\", () => {\n    const input: 'a' | 'b' = 'c' as any;\n    const result = match(input)\n      .with('a', (x) => x)\n      .with('b', (x) => x)\n      .exhaustive((v) => ({ unexpectedValue: v }));\n\n    type t = Expect<\n      Equal<typeof result, { unexpectedValue: unknown } | 'a' | 'b'>\n    >;\n\n    expect(result).toStrictEqual({ unexpectedValue: 'c' });\n  });\n\n  it('should throw otherwise', () => {\n    expect(() => {\n      const input: 'a' | 'b' = 'c' as any;\n      return match(input)\n        .with('a', (x) => x)\n        .with('b', (x) => x)\n        .exhaustive();\n    }).toThrow();\n  });\n\n  it('should return a value assignable to the explicit output type', () => {\n    const input: 'a' | 'b' = 'c' as any;\n    const res = match<typeof input, 'a' | 'b'>(input)\n      .with('a', (x) => x)\n      .with('b', (x) => x)\n      // @ts-expect-error 'c' isn't assignable to a|b\n      .exhaustive(() => {\n        // Note: ideally the error message should be here.\n        return 'c';\n      });\n  });\n\n  it('should return a value assignable .returnType<T>()', () => {\n    const input: 'a' | 'b' = 'c' as any;\n    const res = match(input)\n      .returnType<'a' | 'b'>()\n      .with('a', (x) => x)\n      .with('b', (x) => x)\n      // @ts-expect-error 'c' isn't assignable to a|b\n      .exhaustive(() => 'c');\n  });\n});\n"
  },
  {
    "path": "tests/exhaustive-match.test.ts",
    "content": "import { NonExhaustiveError, match, P } from '../src';\nimport { Equal, Expect } from '../src/types/helpers';\nimport {\n  Option,\n  some,\n  none,\n  BigUnion,\n  State,\n  Event,\n} from './types-catalog/utils';\n\ndescribe('exhaustive()', () => {\n  describe('should exclude matched patterns from subsequent `.with()` clauses', () => {\n    it('string literals', () => {\n      type Input = 'a' | 'b' | 'c';\n      const input = 'b' as Input;\n\n      match(input)\n        .with('b', (x) => {\n          type t = Expect<Equal<typeof x, 'b'>>;\n          return 1;\n        })\n        // @ts-expect-error\n        .exhaustive();\n\n      match(input)\n        .with('a', (x) => 1)\n        .with('b', (x) => 1)\n        // @ts-expect-error\n        .exhaustive();\n\n      match(input)\n        .with('a', (x) => {\n          type t = Expect<Equal<typeof x, 'a'>>;\n          return 1;\n        })\n        .with('b', (x) => {\n          type t = Expect<Equal<typeof x, 'b'>>;\n          return 2;\n        })\n        // @ts-expect-error\n        .exhaustive();\n\n      match(input)\n        .with('a', (x) => {\n          type t = Expect<Equal<typeof x, 'a'>>;\n          return 1;\n        })\n        .with('b', (x) => {\n          type t = Expect<Equal<typeof x, 'b'>>;\n          return 2;\n        })\n        .with('c', (x) => {\n          type t = Expect<Equal<typeof x, 'c'>>;\n          return 2;\n        })\n        .exhaustive();\n    });\n\n    it('number literals', () => {\n      type Input = 1 | 2 | 3;\n      const input = 2 as Input;\n\n      match(input)\n        .with(2, (x) => {\n          type t = Expect<Equal<typeof x, 2>>;\n          return 2;\n        })\n        // @ts-expect-error\n        .exhaustive();\n\n      match(input)\n        .with(1, (x) => 1)\n        .with(2, () => 3)\n        // @ts-expect-error\n        .exhaustive();\n\n      match(input)\n        .with(1, (x) => {\n          type t = Expect<Equal<typeof x, 1>>;\n          return 1;\n        })\n        .with(2, (x) => {\n          type t = Expect<Equal<typeof x, 2>>;\n          return 2;\n        })\n        // @ts-expect-error\n        .exhaustive();\n\n      match(input)\n        .with(1, (x) => {\n          type t = Expect<Equal<typeof x, 1>>;\n          return 1;\n        })\n        .with(2, (x) => {\n          type t = Expect<Equal<typeof x, 2>>;\n          return 2;\n        })\n        .with(3, (x) => {\n          type t = Expect<Equal<typeof x, 3>>;\n          return 2;\n        })\n        .exhaustive();\n    });\n\n    it('boolean literals', () => {\n      type Input =\n        | [true, true]\n        | [false, true]\n        | [false, false]\n        | [true, false];\n      const input = [true, true] as Input;\n\n      match(input)\n        .with([true, true], () => true)\n        .with([false, true], () => false)\n        .with([true, false], () => false)\n        // @ts-expect-error\n        .exhaustive();\n\n      match(input)\n        .with([true, true], () => true)\n        .with([false, true], () => false)\n        .with([true, false], () => false)\n        .with([false, false], () => false)\n        .exhaustive();\n    });\n\n    it('boolean literals', () => {\n      type Input = [boolean, boolean];\n      const input = [true, true] as Input;\n\n      match(input)\n        .with([true, true], () => true)\n        .with([false, true], () => false)\n        .with([true, false], () => false)\n        // @ts-expect-error\n        .exhaustive();\n\n      match(input)\n        .with([true, true], () => true)\n        .with([false, true], () => false)\n        .with([true, false], () => false)\n        .with([false, false], () => false)\n        .exhaustive();\n    });\n\n    it('union of objects', () => {\n      type letter =\n        | 'a'\n        | 'b'\n        | 'c'\n        | 'd'\n        | 'e'\n        | 'f'\n        | 'g'\n        | 'h'\n        | 'i'\n        | 'j'\n        | 'k'\n        | 'l'\n        | 'm'\n        | 'n'\n        | 'o'\n        | 'p'\n        | 'q'\n        | 'r'\n        | 's'\n        | 't'\n        | 'u'\n        | 'v'\n        | 'w'\n        | 'x'\n        | 'y'\n        | 'z';\n\n      type Input =\n        | { type: 1; data: number }\n        | { type: 'two'; data: string }\n        | { type: 3; data: boolean }\n        | { type: 4 }\n        | (letter extends any ? { type: letter } : never);\n\n      const input = { type: 1, data: 2 } as Input;\n\n      match(input)\n        .with({ type: 1 }, (x) => 1)\n        // @ts-expect-error\n        .exhaustive();\n\n      match(input)\n        .with({ type: 1 }, (x) => 1)\n        .with({ type: 'two' }, (x) => 2)\n        // @ts-expect-error\n        .exhaustive();\n\n      match(input)\n        .with({ type: 1, data: P.select() }, (data) => {\n          type t = Expect<Equal<typeof data, number>>;\n          return 1;\n        })\n        .with({ type: 'two', data: P.select() }, (data) => data.length)\n        .with({ type: 3, data: true }, ({ data }) => {\n          type t = Expect<Equal<typeof data, true>>;\n          return 3;\n        })\n        .with({ type: 3, data: P.any }, ({ data }) => {\n          type t = Expect<Equal<typeof data, boolean>>;\n          return 3;\n        })\n        .with({ type: 4 }, () => 3)\n        .with({ type: 'a' }, () => 0)\n        .with({ type: 'b' }, () => 0)\n        .with({ type: 'c' }, () => 0)\n        .with({ type: 'd' }, () => 0)\n        .with({ type: 'e' }, () => 0)\n        .with({ type: 'f' }, () => 0)\n        .with({ type: 'g' }, () => 0)\n        .with({ type: 'h' }, () => 0)\n        .with({ type: 'i' }, () => 0)\n        .with({ type: 'j' }, () => 0)\n        .with({ type: 'k' }, () => 0)\n        .with({ type: 'l' }, () => 0)\n        .with({ type: 'm' }, () => 0)\n        .with({ type: 'n' }, () => 0)\n        .with({ type: 'o' }, () => 0)\n        .with({ type: 'p' }, () => 0)\n        .with({ type: 'q' }, () => 0)\n        .with({ type: 'r' }, () => 0)\n        .with({ type: 's' }, () => 0)\n        .with({ type: 't' }, () => 0)\n        .with({ type: 'u' }, () => 0)\n        .with({ type: 'v' }, () => 0)\n        .with({ type: 'w' }, () => 0)\n        .with({ type: 'x' }, () => 0)\n        .with({ type: 'y' }, () => 0)\n        .with({ type: 'z' }, () => 0)\n        .exhaustive();\n\n      match<Option<number>>({ kind: 'some', value: 3 })\n        .with({ kind: 'some' }, ({ value }) => value)\n        .with({ kind: 'none' }, () => 0)\n        .exhaustive();\n\n      match<Option<number>>({ kind: 'some', value: 3 })\n        .with({ kind: 'some', value: 3 }, ({ value }): number => value)\n        .with({ kind: 'none' }, () => 0)\n        // @ts-expect-error: missing {kind: 'some', value: number}\n        .exhaustive();\n\n      match<Option<number>>({ kind: 'some', value: 3 })\n        .with({ kind: 'some', value: 3 }, ({ value }): number => value)\n        .with({ kind: 'some', value: P.number }, ({ value }): number => value)\n        .with({ kind: 'none' }, () => 0)\n        .exhaustive();\n    });\n\n    it('union of tuples', () => {\n      type Input = [1, number] | ['two', string] | [3, boolean];\n      const input = [1, 3] as Input;\n\n      match(input)\n        .with([1, P.any], (x) => 1)\n        // @ts-expect-error\n        .exhaustive();\n\n      match(input)\n        .with([1, P.any], (x) => 1)\n        .with(['two', P.any], (x) => 2)\n        // @ts-expect-error\n        .exhaustive();\n\n      match(input)\n        .with([1, P.any], (x) => 1)\n        .with(['two', P.any], ([_, data]) => data.length)\n        .with([3, P.any], () => 3)\n        .exhaustive();\n\n      match(input)\n        .with([1, P.any], (x) => 1)\n        .with(['two', 'Hey'], ([_, data]) => data.length)\n        .with(['two', P.any], ([_, data]) => data.length)\n        .with([3, P.any], () => 3)\n        .exhaustive();\n    });\n\n    it('deeply nested 1', () => {\n      type Input =\n        | [1, Option<number>]\n        | ['two', Option<string>]\n        | [3, Option<boolean>];\n      const input = [1, { kind: 'some', value: 3 }] as Input;\n\n      match(input)\n        .with([1, { kind: 'some' }], (x) => 1)\n        // @ts-expect-error\n        .exhaustive();\n\n      match(input)\n        .with([1, P.any], (x) => 1)\n        .with(['two', P.any], (x) => 2)\n        // @ts-expect-error\n        .exhaustive();\n\n      match(input)\n        .with([1, P._], (x) => 1)\n        .with(['two', { kind: 'some' }], ([_, { value }]) => value.length)\n        .with([3, P._], () => 3)\n        // @ts-expect-error\n        .exhaustive();\n\n      match(input)\n        .with(['two', { kind: 'some' }], ([_, { value }]) => value.length)\n        .with(['two', { kind: 'none' }], () => 4)\n        .with([1, P._], () => 3)\n        .with([3, P._], () => 3)\n        .exhaustive();\n    });\n\n    it('deeply nested 2', () => {\n      type Input = ['two', Option<string>];\n      const input = ['two', { kind: 'some', value: 'hello' }] as Input;\n\n      match(input)\n        .with(['two', { kind: 'some' }], ([_, { value }]) => value.length)\n        .with(['two', { kind: 'none' }], () => 4)\n        .exhaustive();\n    });\n\n    it('should work with non-unions', () => {\n      match<number>(2)\n        .with(2, () => 'two')\n        .with(3, () => 'three')\n        // @ts-expect-error\n        .exhaustive();\n\n      match<number>(2)\n        .with(2, () => 'two')\n        .with(3, () => 'three')\n        .with(P.number, () => 'something else')\n        .exhaustive();\n\n      match<string>('Hello')\n        .with('Hello', () => 'english')\n        .with('Bonjour', () => 'french')\n        // @ts-expect-error\n        .exhaustive();\n\n      match<string>('Hello')\n        .with('Hello', () => 'english')\n        .with('Bonjour', () => 'french')\n        .with(P.any, (c) => 'something else')\n        .exhaustive();\n    });\n\n    it('should work with object properties union', () => {\n      type Input = { value: 'a' | 'b' };\n      const input = { value: 'a' } as Input;\n\n      match(input)\n        .with({ value: 'a' }, (x) => 1)\n        // @ts-expect-error\n        .exhaustive();\n\n      match(input)\n        .with({ value: P.any }, (x) => 1)\n        .exhaustive();\n\n      match(input)\n        .with({ value: 'a' }, (x) => 1)\n        .with({ value: 'b' }, (x) => 1)\n        .exhaustive();\n    });\n\n    it('should work with lists', () => {\n      type Input =\n        | {\n            type: 'a';\n            items: ({ some: string; data: number } | string)[];\n          }\n        | {\n            type: 'b';\n            items: { other: boolean; data: string }[];\n          };\n\n      const input = {\n        type: 'a',\n        items: [{ some: 'hello', data: 42 }],\n      } as Input;\n\n      match(input)\n        .with({ type: 'a' }, (x) => x.items)\n        // @ts-expect-error\n        .exhaustive();\n\n      match(input)\n        .with({ type: 'a' }, (x) => x.items)\n        .with({ type: 'b', items: P.array({ data: P.string }) }, (x) => [])\n        .exhaustive();\n\n      match(input)\n        .with({ type: 'a', items: P.array(P.any) }, (x) => x.items)\n        .with({ type: 'b', items: P.array({ data: P.string }) }, (x) => [])\n        .exhaustive();\n\n      match<Input>(input)\n        .with({ type: 'a', items: P.array({ some: P.any }) }, (x) => x.items)\n        .with({ type: 'b', items: P.array({ data: P.string }) }, (x) => [])\n        // @ts-expect-error\n        .exhaustive();\n    });\n\n    it('should support P.any in a readonly tuple', () => {\n      const f = (n: number, state: State) => {\n        const x = match([n, state])\n          .with(\n            [1, { status: 'success', data: P.select() }],\n            ([_, { data }]) => data.startsWith('coucou'),\n            (data) => data.replace('coucou', 'bonjour')\n          )\n          .with([2, P.any], () => \"It's a twoooo\")\n          .with([P.any, { status: 'error' }], () => 'Oups')\n          .with([P.any, { status: 'idle' }], () => '')\n          .with([P.any, { status: 'loading' }], () => '')\n          .with([P.any, { status: 'success' }], () => '')\n          .exhaustive();\n      };\n    });\n\n    it('should work with Sets', () => {\n      type Input = Set<string> | Set<number>;\n      const input = new Set(['']) as Input;\n\n      match(input)\n        .with(P.set(P.string), (x) => x)\n        // @ts-expect-error\n        .exhaustive();\n\n      match(input)\n        .with(P.set(P.string), (x) => x)\n        .with(P.set(P.number), (x) => new Set([]))\n        .exhaustive();\n    });\n\n    it('should work with Sets', () => {\n      type Input = Set<string> | Set<number>;\n      const input = new Set(['']) as Input;\n\n      expect(\n        match(input)\n          .with(P.set(P.string), (x) => x)\n          // @ts-expect-error\n          .exhaustive()\n      ).toEqual(input);\n\n      expect(\n        match(input)\n          .with(P.set(P.string), (x) => 1)\n          .with(P.set(P.number), (x) => 2)\n          .exhaustive()\n      ).toEqual(1);\n    });\n\n    it('should work with Maps', () => {\n      type Input = Map<string, 1 | 2 | 3>;\n      const input = new Map([['hello', 1]]) as Input;\n\n      expect(\n        match(input)\n          .with(P.map('hello', P.number), (x) => x)\n          // @ts-expect-error\n          .exhaustive()\n      ).toEqual(input);\n\n      expect(\n        match(input)\n          .with(P.map('hello', 1), (x) => x)\n          // @ts-expect-error\n          .exhaustive()\n      ).toEqual(input);\n\n      expect(\n        match(input)\n          .with(P.map('hello', 1), (x) => x)\n          // @ts-expect-error\n          .exhaustive()\n      ).toEqual(input);\n\n      match(input)\n        .with(P.any, (x) => x)\n        .exhaustive();\n    });\n\n    it('should work with structures with a lot of unions', () => {\n      type X = 1 | 2 | 3 | 4 | 5 | 6 | 7;\n      // This structures has 7 ** 9 = 40353607 possibilities\n      match<{\n        a: X;\n        b: X;\n        c: X;\n        d: X;\n        e: X;\n        f: X;\n        g: X;\n        h: X;\n        i: X;\n      }>({ a: 1, b: 1, c: 1, d: 1, e: 1, f: 1, g: 1, h: 1, i: 1 })\n        .with({ b: 1 }, () => 'otherwise')\n        .with({ b: 2 }, () => 'b = 2')\n        .with({ b: 3 }, () => 'otherwise')\n        .with({ b: 4 }, () => 'otherwise')\n        .with({ b: 5 }, () => 'otherwise')\n        .with({ b: 6 }, () => 'otherwise')\n        .with({ b: 7 }, () => 'otherwise')\n        .exhaustive();\n\n      match<{\n        a: X;\n        b: X;\n        c: X;\n      }>({ a: 1, b: 1, c: 1 })\n        .with({ a: P.not(1) }, () => 'a != 1')\n        .with({ a: 1 }, () => 'a != 1')\n        .exhaustive();\n\n      match<{\n        a: BigUnion;\n        b: BigUnion;\n      }>({ a: 'a', b: 'b' })\n        .with({ a: 'a' }, () => 0)\n        .with({ a: 'b' }, () => 0)\n        .with({ a: 'c' }, (x) => 0)\n        .with({ a: 'd' }, () => 0)\n        .with({ a: 'e' }, (x) => 0)\n        .with({ a: 'f', b: P.any }, (x) => 0)\n        .with({ a: P.any }, (x) => 0)\n        .exhaustive();\n    });\n\n    it('should work with generics', () => {\n      const last = <a>(xs: a[]) =>\n        match<a[], Option<a>>(xs)\n          .with([], () => none)\n          .with(P.any, (x, y) => some(xs[xs.length - 1]))\n          .exhaustive();\n\n      expect(last([1, 2, 3])).toEqual(some(3));\n    });\n\n    it('should work with generics in type guards', () => {\n      const map = <A, B>(\n        option: Option<A>,\n        mapper: (value: A) => B\n      ): Option<B> =>\n        match<Option<A>, Option<B>>(option)\n          .when(\n            (option): option is { kind: 'some'; value: A } =>\n              option.kind === 'some',\n            (option) => ({\n              kind: 'some',\n              value: mapper(option.value),\n            })\n          )\n          .when(\n            (option): option is { kind: 'none' } => option.kind === 'none',\n            (option) => option\n          )\n          .otherwise(() => ({ kind: 'none' }));\n\n      const res = map(\n        { kind: 'some' as const, value: 20 },\n        (x) => `number is ${x}`\n      );\n\n      type t = Expect<Equal<typeof res, Option<string>>>;\n\n      expect(res).toEqual({ kind: 'some' as const, value: `number is 20` });\n    });\n\n    it('should work with inputs of varying shapes', () => {\n      type Input = { type: 'test' } | ['hello', Option<string>] | 'hello'[];\n      const input = { type: 'test' } as Input;\n\n      expect(\n        match(input)\n          .with(['hello', { kind: 'some' }], ([, { value }]) => {\n            return value;\n          })\n          .with(['hello'], ([str]) => {\n            return str;\n          })\n          .with({ type: P.any }, (x) => x.type)\n          .with(P.array(P.any), (x) => {\n            type t = Expect<\n              Equal<typeof x, 'hello'[] | ('hello' | Option<string>)[]>\n            >;\n            return `(\"hello\" | Option<string>)[] | \"hello\"[]`;\n          })\n          .exhaustive()\n      ).toEqual('test');\n    });\n\n    it('should infer literals as literal types', () => {\n      type Input = { type: 'video'; duration: number };\n\n      match<Input>({ type: 'video', duration: 10 })\n        .with({ type: 'video', duration: 10 }, (x) => '')\n        // @ts-expect-error\n        .exhaustive();\n\n      let n: number = 10;\n      match<number>(n)\n        .with(10, (x) => '')\n        // @ts-expect-error\n        .exhaustive();\n    });\n\n    it('should correctly exclude cases if when pattern contains a type guard', () => {\n      match<{ x: 1 | 2 | 3 }>({ x: 2 })\n        .with({ x: P.when((x): x is 1 => x === 1) }, (x) => {\n          type t = Expect<Equal<typeof x, { x: 1 }>>;\n          return '';\n        })\n        .with({ x: P.when((x): x is 2 => x === 2) }, (x) => {\n          type t = Expect<Equal<typeof x, { x: 2 }>>;\n          return '';\n        })\n        .with({ x: P.when((x): x is 3 => x === 3) }, (x) => {\n          type t = Expect<Equal<typeof x, { x: 3 }>>;\n          return '';\n        })\n        .exhaustive();\n    });\n\n    it('should correctly exclude cases if .when is a type guard', () => {\n      match<Option<string>, Option<number>>({ kind: 'none' })\n        .when(\n          (option): option is { kind: 'some'; value: string } =>\n            option.kind === 'some',\n          (option) => ({\n            kind: 'some',\n            value: option.value.length,\n          })\n        )\n        .when(\n          (option): option is { kind: 'none' } => option.kind === 'none',\n          (option) => option\n        )\n        .exhaustive();\n    });\n\n    it('should correctly exclude cases if the pattern is a literal type', () => {\n      const input = { kind: 'none' } as Option<string>;\n      match(input)\n        .with({ kind: 'some', value: 'hello' }, (option) => '')\n        .with({ kind: 'none' }, (option) => '')\n        // @ts-expect-error: handled { kind: 'some', value: string }\n        .exhaustive();\n\n      match(input)\n        .with({ kind: 'some', value: 'hello' }, (option) => '')\n        .with({ kind: 'none' }, (option) => '')\n        .with({ kind: 'some' }, (option) => '')\n        .exhaustive();\n    });\n\n    it('should not exclude cases if the pattern is a literal type and the value is not', () => {\n      match<{ x: number }>({ x: 2 })\n        .with({ x: 2 }, ({ x }) => {\n          type t = Expect<Equal<typeof x, 2>>;\n          return '';\n        })\n        // @ts-expect-error\n        .exhaustive();\n\n      match<1 | 2 | 3>(2)\n        .with(2, (x) => {\n          type t = Expect<Equal<typeof x, 2>>;\n          return '';\n        })\n        // @ts-expect-error\n        .exhaustive();\n\n      match<1 | 2 | 3>(2)\n        .with(1, (x) => {\n          type t = Expect<Equal<typeof x, 1>>;\n          return '';\n        })\n        .with(2, (x) => {\n          type t = Expect<Equal<typeof x, 2>>;\n          return '';\n        })\n        .with(3, (x) => {\n          type t = Expect<Equal<typeof x, 3>>;\n          return '';\n        })\n        .exhaustive();\n    });\n  });\n\n  it('real world example', () => {\n    type Input =\n      | { type: 'text'; text: string; author: { name: string } }\n      | { type: 'video'; duration: number; src: string }\n      | {\n          type: 'movie';\n          duration: number;\n          author: { name: string };\n          src: string;\n          title: string;\n        }\n      | { type: 'picture'; src: string };\n\n    const isNumber = (x: unknown): x is number => typeof x === 'number';\n\n    match<Input>({ type: 'text', text: 'Hello', author: { name: 'Gabriel' } })\n      .with(\n        {\n          type: 'text',\n          text: P.select('text'),\n          author: { name: P.select('authorName') },\n        },\n        ({ text, authorName }) => `${text} from ${authorName}`\n      )\n      .with({ type: 'video', duration: P.when((x) => x > 10) }, () => '')\n      .with(\n        {\n          type: 'video',\n          duration: P.when(isNumber),\n        },\n        () => ''\n      )\n      .with({ type: 'movie', duration: 10 }, () => '')\n      .with(\n        {\n          type: 'movie',\n          duration: 10,\n          author: P.select('author'),\n          title: P.select('title'),\n        },\n        ({ author, title }) => ''\n      )\n      .with({ type: 'picture' }, () => '')\n      .with({ type: 'movie', duration: P.when(isNumber) }, () => '')\n      .exhaustive();\n  });\n\n  it('reducer example', () => {\n    const initState: State = {\n      status: 'idle',\n    };\n\n    const reducer = (state: State, event: Event): State =>\n      match<[State, Event], State>([state, event])\n        .with(\n          [{ status: 'loading' }, { type: 'success', data: P.select() }],\n          (data) => ({ status: 'success', data })\n        )\n        .with(\n          [{ status: 'loading' }, { type: 'error', error: P.select() }],\n          (error) => ({ status: 'error', error })\n        )\n        .with([{ status: 'loading' }, { type: 'cancel' }], () => initState)\n\n        .with([{ status: P.not('loading') }, { type: 'fetch' }], (value) => ({\n          status: 'loading',\n        }))\n        .with(P._, () => state)\n        .exhaustive();\n  });\n\n  it('select should always match', () => {\n    type Input = { type: 3; data: number };\n\n    const input = { type: 3, data: 2 } as Input;\n\n    match<Input>(input)\n      .with({ type: 3, data: P.select() }, (data) => {\n        type t = Expect<Equal<typeof data, number>>;\n        return 3;\n      })\n      .exhaustive();\n\n    type Input2 = { type: 3; data: true } | 2;\n    match<Input2>(2)\n      .with({ type: 3, data: P.select() }, (data) => {\n        type t = Expect<Equal<typeof data, true>>;\n        return 3;\n      })\n      .with(2, () => 2)\n      .exhaustive();\n  });\n\n  describe('Exhaustive match with runtime error', () => {\n    type FlagComponent = { color: 'red' | 'white' | 'blue' };\n\n    function checkFlagComponent(component: FlagComponent) {\n      return match(component)\n        .with({ color: 'red' }, () => {\n          throw new Error('Red error');\n        })\n        .with({ color: 'white' }, () => {\n          throw new Error('White error');\n        })\n        .with({ color: 'blue' }, () => {\n          throw new Error('Blue error');\n        })\n        .exhaustive();\n    }\n\n    it('Unmatched pattern results in NonExhaustiveError', () => {\n      expect.assertions(3);\n      const input = { color: 'orange' } as unknown as FlagComponent;\n\n      try {\n        checkFlagComponent(input);\n      } catch (e) {\n        const err = e as NonExhaustiveError;\n        expect(err).toBeInstanceOf(NonExhaustiveError);\n        expect(err.message).toEqual(\n          'Pattern matching error: no pattern matches value {\"color\":\"orange\"}'\n        );\n        expect(err.input).toStrictEqual(input);\n      }\n    });\n\n    it('Matched pattern with callback error does not result in NonExhaustiveError', () => {\n      expect.assertions(3);\n\n      try {\n        checkFlagComponent({ color: 'blue' });\n      } catch (e) {\n        const err = e as Error;\n        expect(err).toBeInstanceOf(Error);\n        expect(err).not.toBeInstanceOf(NonExhaustiveError);\n        expect(err.message).toEqual('Blue error');\n      }\n    });\n  });\n\n  describe('Exhaustive match and `not` patterns', () => {\n    it('should work with a single not pattern', () => {\n      const reducer1 = (state: State, event: Event): State =>\n        match<[State, Event], State>([state, event])\n          .with([{ status: P.not('loading') }, P.any], (x) => state)\n          .with([{ status: 'loading' }, { type: 'fetch' }], () => state)\n          // @ts-expect-error\n          .exhaustive();\n\n      const reducer3 = (state: State, event: Event): State =>\n        match<[State, Event], State>([state, event])\n          .with([{ status: P.not('loading') }, P.any], (x) => state)\n          .with([{ status: 'loading' }, P.any], () => state)\n          .exhaustive();\n    });\n\n    it('should work with several not patterns', () => {\n      const reducer = (state: State, event: Event): State =>\n        match<[State, Event], State>([state, event])\n          .with(\n            [{ status: P.not('loading') }, { type: P.not('fetch') }],\n            (x) => state\n          )\n          .with([{ status: 'loading' }, { type: P.any }], () => state)\n          .with([{ status: P.any }, { type: 'fetch' }], () => state)\n          .exhaustive();\n\n      const f = (input: readonly [1 | 2 | 3, 1 | 2 | 3, 1 | 2 | 3]) =>\n        match(input)\n          .with([P.not(1), P.not(1), P.not(1)], (x) => 'ok')\n          .with([1, P._, P._], () => 'ok')\n          .with([P._, 1, P._], () => 'ok')\n          .with([P._, P._, 1], () => 'ok')\n          .exhaustive();\n\n      const range = [1, 2, 3] as const;\n      const flatMap = <A, B>(\n        xs: readonly A[],\n        f: (x: A) => readonly B[]\n      ): B[] => xs.reduce<B[]>((acc, x) => acc.concat(f(x)), []);\n\n      const allPossibleCases = flatMap(range, (x) =>\n        flatMap(range, (y) => flatMap(range, (z) => [[x, y, z]] as const))\n      );\n\n      allPossibleCases.forEach((x) => expect(f(x)).toBe('ok'));\n\n      const f2 = (input: [1 | 2 | 3, 1 | 2 | 3, 1 | 2 | 3]) =>\n        match(input)\n          .with([P.not(1), P.not(1), P.not(1)], (x) => 'ok')\n          .with([1, P.any, P.any], () => 'ok')\n          .with([P.any, 1, P.any], () => 'ok')\n          // @ts-expect-error : NonExhaustiveError<[3, 3, 1] | [3, 2, 1] | [2, 3, 1] | [2, 2, 1]>\n          .exhaustive();\n    });\n\n    it('should work with not patterns and lists', () => {\n      const f = (input: (1 | 2 | 3)[]) =>\n        match(input)\n          .with([P.not(1)], (x) => 'ok')\n          .with([1], (x) => 'ok')\n          // @ts-expect-error: NonExhaustiveError<(1 | 2 | 3)[]>, because lists can be heterogenous\n          .exhaustive();\n    });\n  });\n\n  describe('exhaustive and any', () => {\n    const f = (input: { t: 'a'; x: any } | { t: 'b' }) =>\n      match(input)\n        .with({ t: 'a' }, (x) => {\n          type t = Expect<Equal<typeof x, { t: 'a'; x: any }>>;\n          return 'ok';\n        })\n        .with({ t: 'b' }, (x) => 'ok')\n        .exhaustive();\n\n    const f2 = (input: { t: 'a'; x: any } | { t: 'b' }) =>\n      match(input)\n        .with({ t: 'a', x: 'hello' }, (x) => 'ok')\n        .with({ t: 'b' }, (x) => 'ok')\n        // FIXME should error @ts-expect-error\n        .exhaustive();\n\n    const f3 = (input: { t: 'a'; x: any } | { t: 'b' }) =>\n      match(input)\n        .with({ t: 'a', x: P.any }, (x) => 'ok')\n        .with({ t: 'b' }, (x) => 'ok')\n        .exhaustive();\n  });\n\n  describe('issue #44', () => {\n    it(\"shouldn't exclude cases if the pattern contains unknown keys\", () => {\n      type Person = {\n        sex: 'a' | 'b';\n        age: 'c' | 'd';\n      };\n\n      function withTypo(person: Person) {\n        return (\n          match(person)\n            //   this pattern contains an addition unknown key\n            .with({ sex: 'b', oopsThisIsATypo: 'c' }, (x) => {\n              // The unknown key should be added to the object type\n              type t = Expect<\n                Equal<\n                  typeof x,\n                  {\n                    age: 'c' | 'd';\n                    sex: 'b';\n                    oopsThisIsATypo: 'c';\n                  }\n                >\n              >;\n              return 1;\n            })\n            // those are correct\n            .with({ sex: 'b', age: 'd' }, () => 2)\n            .with({ sex: 'a', age: 'c' }, () => 3)\n            .with({ sex: 'a', age: 'd' }, () => 4)\n            // this pattern shouldn't be considered exhaustive\n            // @ts-expect-error\n            .exhaustive()\n        );\n      }\n\n      function withoutTypo(person: Person) {\n        return (\n          match(person)\n            .with({ sex: 'b', age: 'c' }, (x) => 1)\n            .with({ sex: 'b', age: 'd' }, () => 2)\n            .with({ sex: 'a', age: 'c' }, () => 3)\n            .with({ sex: 'a', age: 'd' }, () => 4)\n            // this should be ok\n            .exhaustive()\n        );\n      }\n\n      expect(() => withTypo({ sex: 'b', age: 'c' })).toThrow();\n      expect(withoutTypo({ sex: 'b', age: 'c' })).toBe(1);\n    });\n  });\n\n  it('issue #271: P.array should exhaustively match readonly arrays', () => {\n    type Input = string | Date | readonly string[];\n    const input = ['a', 'b', 'c'] as Input;\n\n    const output = match(input)\n      .with(P.array(P.string), (value) => 1)\n      .with(P.string, (value) => 2)\n      .with(P.instanceOf(Date), (value) => 3)\n      .exhaustive();\n  });\n\n  describe('issue #278: should support exhaustive check on optional property', () => {\n    // https://github.com/gvergnaud/ts-pattern/issues/278\n\n    type Input = { type?: 'one' } | { type: 'two' };\n\n    it(\"exhaustive should fail when the optional key isn't provided\", () => {\n      const f = (input: Input) =>\n        match(input)\n          .with({ type: 'one' }, (x) => {\n            return false;\n          })\n          .with({ type: 'two' }, (x) => {\n            return false;\n          })\n          // @ts-expect-error\n          .exhaustive();\n\n      expect(f({ type: 'one' })).toBe(false);\n      expect(f({ type: 'two' })).toBe(false);\n      expect(() => f({})).toThrow();\n    });\n\n    it('exhaustive should fail when matching on { type: undefined }', () => {\n      // Because { type: undefined } doesn't match when passing an empty object –\n      // the key must be present on the object.\n      const f = (input: Input) =>\n        match(input)\n          .with({ type: 'one' }, (x) => {\n            return false;\n          })\n          .with({ type: 'two' }, (x) => {\n            return false;\n          })\n          .with({ type: undefined }, (x) => {\n            type t = Expect<Equal<typeof x, { type: undefined }>>;\n            return true;\n          })\n          // @ts-expect-error\n          .exhaustive();\n\n      expect(f({ type: 'one' })).toBe(false);\n      expect(f({ type: 'two' })).toBe(false);\n      expect(f({ type: undefined })).toBe(true);\n      expect(() => f({})).toThrow();\n    });\n\n    it('exhaustive should pass when using P.optional(undefined)', () => {\n      const f = (input: Input) =>\n        match(input)\n          .with({ type: 'one' }, (x) => {\n            return false;\n          })\n          .with({ type: 'two' }, (x) => {\n            return false;\n          })\n          .with({ type: P.optional(undefined) }, (x) => {\n            type t = Expect<Equal<typeof x, { type?: undefined }>>;\n            return true;\n          })\n          .exhaustive();\n\n      expect(f({ type: 'one' })).toBe(false);\n      expect(f({ type: 'two' })).toBe(false);\n      expect(f({ type: undefined })).toBe(true);\n      expect(f({})).toBe(true);\n    });\n\n    it('exhaustive should pass when using {} and { type: undefined }', () => {\n      const f = (input: Input) =>\n        match(input)\n          .with({ type: 'one' }, (x) => {\n            return false;\n          })\n          .with({ type: 'two' }, (x) => {\n            return false;\n          })\n          .with({ type: undefined }, (x) => {\n            type t = Expect<Equal<typeof x, { type: undefined }>>;\n            return true;\n          })\n          .with({}, (x) => {\n            return true;\n          })\n          .exhaustive();\n\n      expect(f({ type: 'one' })).toBe(false);\n      expect(f({ type: 'two' })).toBe(false);\n      expect(f({ type: undefined })).toBe(true);\n      expect(f({})).toBe(true);\n    });\n  });\n});\n"
  },
  {
    "path": "tests/extract-precise-value.test.ts",
    "content": "import { ExtractPreciseValue } from '../src/types/ExtractPreciseValue';\nimport { InvertPattern } from '../src/types/InvertPattern';\nimport { NonNullablePattern } from '../src/types/Pattern';\nimport { Expect, Equal } from '../src/types/helpers';\nimport { AsyncResult, Event, Option, State } from './types-catalog/utils';\n\ndescribe('ExtractPreciseValue', () => {\n  it('should correctly extract the matching value from the input and an inverted pattern', () => {\n    type res1 = ExtractPreciseValue<\n      { type: 'test' } | ['hello', Option<string>] | 'hello'[],\n      ['hello', { kind: 'some' }]\n    >;\n\n    type test1 = Expect<\n      Equal<res1, ['hello', { kind: 'some'; value: string }]>\n    >;\n\n    type cases = [\n      Expect<\n        Equal<\n          ExtractPreciseValue<\n            | { type: 'a'; message: string }\n            | { type: 'b'; count: number }\n            | { type: 'c'; count: number },\n            { count: number }\n          >,\n          { type: 'b'; count: number } | { type: 'c'; count: number }\n        >\n      >,\n      Expect<\n        Equal<\n          ExtractPreciseValue<\n            | {\n                type: 'a';\n                x: { type: 'b'; count: number } | { type: 'c'; count: number };\n                y: 'other';\n              }\n            | { type: 'b'; count: number }\n            | { type: 'c'; count: number },\n            { type: 'a'; x: { type: 'b' } }\n          >,\n          {\n            type: 'a';\n            x: { type: 'b'; count: number };\n            y: 'other';\n          }\n        >\n      >,\n      Expect<\n        Equal<\n          ExtractPreciseValue<\n            | {\n                type: 'a';\n                x:\n                  | { type: 'b'; count: number }\n                  | { type: 'c'; count: number }\n                  | { type: 'd' };\n                y: 'other';\n              }\n            | { type: 'b'; count: number }\n            | { type: 'c'; count: number },\n            { type: 'a'; x: { count: number } }\n          >,\n          {\n            type: 'a';\n            x: { type: 'b'; count: number } | { type: 'c'; count: number };\n            y: 'other';\n          }\n        >\n      >\n    ];\n  });\n\n  it('should use the type of the pattern if the input is any or never', () => {\n    type cases = [\n      Expect<\n        Equal<\n          ExtractPreciseValue<any, ['hello', { kind: 'some' }]>,\n          ['hello', { kind: 'some' }]\n        >\n      >\n    ];\n  });\n\n  it('should return the input type when pattern is unknown', () => {\n    type cases = [\n      Expect<\n        Equal<\n          ExtractPreciseValue<[State, Event], [unknown, unknown]>,\n          [State, Event]\n        >\n      >\n    ];\n  });\n\n  it('should return the correct branch a union based on the pattern', () => {\n    type cases = [\n      Expect<\n        Equal<\n          ExtractPreciseValue<\n            { a: string; b: number } | [boolean, number],\n            readonly [true, 2]\n          >,\n          [true, 2]\n        >\n      >,\n      Expect<\n        Equal<\n          ExtractPreciseValue<\n            | {\n                type: 'img';\n                src: string;\n              }\n            | {\n                type: 'text';\n                p: string;\n              }\n            | {\n                type: 'video';\n                src: number;\n              }\n            | {\n                type: 'gif';\n                p: string;\n              }\n            | undefined,\n            {\n              type: 'video';\n              src: unknown;\n            }\n          >,\n          {\n            type: 'video';\n            src: number;\n          }\n        >\n      >\n    ];\n  });\n\n  it('should support readonly input types', () => {\n    type cases = [\n      Expect<\n        Equal<\n          ExtractPreciseValue<\n            { readonly a: string; b: number } | [boolean, number],\n            readonly [true, 2]\n          >,\n          [true, 2]\n        >\n      >,\n      Expect<\n        Equal<\n          ExtractPreciseValue<\n            { readonly a: string; b: number } | [boolean, number],\n            { b: number }\n          >,\n          { readonly a: string; b: number }\n        >\n      >,\n      Expect<\n        Equal<\n          ExtractPreciseValue<\n            { readonly a: string; b: number } | [boolean, number],\n            { readonly a: string }\n          >,\n          { readonly a: string; b: number }\n        >\n      >\n    ];\n  });\n\n  it('should work if the input type contains anys', () => {\n    type Input = { t: 'a'; data: 'string'; x: any } | { t: 'b' };\n\n    type cases = [\n      Expect<\n        Equal<\n          ExtractPreciseValue<Input, { t: 'a' }>,\n          { t: 'a'; data: 'string'; x: any }\n        >\n      >,\n      Expect<Equal<ExtractPreciseValue<Input, { t: 'b' }>, { t: 'b' }>>,\n\n      Expect<\n        Equal<\n          ExtractPreciseValue<[string | number, any], [string, unknown]>,\n          [string, any]\n        >\n      >,\n      Expect<\n        Equal<\n          ExtractPreciseValue<[number, any] | ['t', 2], ['t', unknown]>,\n          ['t', 2]\n        >\n      >,\n\n      Expect<\n        Equal<\n          ExtractPreciseValue<\n            [\n              { t: 'a' } | { t: 'b'; data: any },\n              { t: 'a'; x: boolean } | { t: 'b' }\n            ],\n            [{ t: 'b' }, { t: 'a' }]\n          >,\n          [{ t: 'b'; data: any }, { t: 'a'; x: boolean }]\n        >\n      >\n    ];\n  });\n\n  it('should work with arrays', () => {\n    type res1 = ExtractPreciseValue<\n      boolean | { type: string } | string[],\n      string[]\n    >;\n    type test1 = Expect<Equal<res1, string[]>>;\n\n    type res2 = ExtractPreciseValue<\n      ({ a: string } | { b?: number | boolean; c: string })[],\n      { b: number }[]\n    >;\n    type test2 = Expect<Equal<res2, { b: number; c: string }[]>>;\n  });\n\n  describe('Optional properties', () => {\n    it('should pick the input type as the upper bound, even if it is assignable to the pattern type', () => {\n      // This happens if the input type only has optional properties\n      type Input =\n        | { type: 'test'; id?: string }\n        | { type: 'test2'; id?: string; otherProp: string }\n        | { type: 'test3'; id?: string; otherProp?: string };\n\n      type cases = [\n        Expect<\n          Equal<\n            ExtractPreciseValue<Input, { type: 'test' }>,\n            { type: 'test'; id?: string }\n          >\n        >,\n        Expect<\n          Equal<\n            ExtractPreciseValue<Input, { type: 'test2' }>,\n            { type: 'test2'; id?: string; otherProp: string }\n          >\n        >,\n        Expect<\n          Equal<\n            ExtractPreciseValue<Input, { type: 'test3' }>,\n            { type: 'test3'; id?: string; otherProp?: string }\n          >\n        >\n      ];\n    });\n\n    it('should keep optional properties if they are optional on both `a` and `b`', () => {\n      type Input =\n        | {\n            type: 'a';\n            data?: { type: 'img'; src: string } | { type: 'text'; p: string };\n          }\n        | {\n            type: 'b';\n            data?: { type: 'video'; src: number } | { type: 'gif'; p: string };\n          };\n\n      type cases = [\n        Expect<\n          Equal<\n            ExtractPreciseValue<\n              Input,\n              {\n                type: 'a';\n                data?: { type: 'img' } | undefined;\n              }\n            >,\n            {\n              type: 'a';\n              data?: { type: 'img'; src: string } | undefined;\n            }\n          >\n        >,\n        Expect<\n          Equal<\n            ExtractPreciseValue<\n              { data: { type?: 'a'; value: number } },\n              { data: { type?: 'a' } }\n            >,\n            { data: { type?: 'a'; value: number } }\n          >\n        >\n      ];\n    });\n  });\n\n  describe('non-nullable patterns', () => {\n    type nonNullable = InvertPattern<NonNullablePattern, unknown>;\n\n    it('should exclude objects if the absent', () => {\n      type res1 = ExtractPreciseValue<{ a: string }, { b: nonNullable }>;\n      type test1 = Expect<Equal<res1, never>>;\n\n      type res2 = ExtractPreciseValue<\n        { a: string } | { b: number },\n        { b: nonNullable }\n      >;\n      type test2 = Expect<Equal<res2, { b: number }>>;\n\n      type res3 = ExtractPreciseValue<\n        { a: string } | { b: number } | { b: string; c: boolean },\n        { b: nonNullable }\n      >;\n      type test3 = Expect<\n        Equal<res3, { b: number } | { b: string; c: boolean }>\n      >;\n    });\n\n    it('should keep empty objects if they come from the input type', () => {\n      type res1 = ExtractPreciseValue<\n        { a: string } | { b: {} },\n        { b: nonNullable }\n      >;\n      type test1 = Expect<Equal<res1, { b: {} }>>;\n    });\n\n    it('should exclude objects even if the non-nullable key is deeply nested', () => {\n      type res1 = ExtractPreciseValue<{ a: number }, { b: { c: nonNullable } }>;\n      type test1 = Expect<Equal<res1, never>>;\n\n      type res2 = ExtractPreciseValue<\n        | { nested: { a: string } }\n        | { nested: { b: number } }\n        | { nested: { b: string; c: boolean } },\n        { nested: { b: nonNullable } }\n      >;\n      type test2 = Expect<\n        Equal<\n          res2,\n          { nested: { b: number } } | { nested: { b: string; c: boolean } }\n        >\n      >;\n    });\n  });\n\n  describe('Branded strings', () => {\n    it('Type narrowing should correctly work on branded strings', () => {\n      // Branded strings is a commonly used way of implementing\n      // nominal types in typescript.\n\n      type BrandedId = string & { __brand: 'brandId' };\n\n      type FooBar =\n        | { type: 'foo'; id: BrandedId; value: string }\n        | { type: 'bar' };\n\n      type cases = [\n        Expect<\n          Equal<\n            ExtractPreciseValue<\n              {\n                fooBar: FooBar;\n                fooBarId: BrandedId;\n              },\n              {\n                fooBar: { type: 'foo' };\n                fooBarId: BrandedId;\n              }\n            >,\n            {\n              fooBar: {\n                type: 'foo';\n                id: BrandedId;\n                value: string;\n              };\n              fooBarId: BrandedId;\n            }\n          >\n        >\n      ];\n    });\n  });\n\n  describe('class instances', () => {\n    it('Type narrowing should correctly work on class instances', () => {\n      class A {\n        a = 'a';\n      }\n      class B {\n        b = 'b';\n      }\n      type cases = [Expect<Equal<ExtractPreciseValue<A | B, A>, A>>];\n    });\n\n    it('issue #63: it should correctly narrow Error subclasses', () => {\n      class FooError extends Error {\n        foo = 'bar';\n      }\n\n      class BazError extends Error {\n        baz = 'bil';\n      }\n\n      class ErrorWithOptionalKeys1 extends Error {\n        foo?: string;\n      }\n\n      class ErrorWithOptionalKeys2 extends Error {\n        baz?: string;\n      }\n\n      type cases = [\n        Expect<\n          Equal<\n            ExtractPreciseValue<FooError | BazError | Error, FooError>,\n            FooError\n          >\n        >,\n        Expect<\n          Equal<\n            ExtractPreciseValue<\n              | ErrorWithOptionalKeys1\n              | ErrorWithOptionalKeys2\n              | ErrorWithOptionalKeys1,\n              ErrorWithOptionalKeys1\n            >,\n            ErrorWithOptionalKeys1\n          >\n        >\n      ];\n    });\n  });\n\n  describe('variadic patterns', () => {\n    it('[a, ...b[]]', () => {\n      type res1 = ExtractPreciseValue<unknown[], [unknown, ...unknown[]]>;\n      type t1 = Expect<Equal<res1, [unknown, ...unknown[]]>>;\n\n      type res2 = ExtractPreciseValue<unknown[], [number, ...string[]]>;\n      type t2 = Expect<Equal<res2, [number, ...string[]]>>;\n\n      type res3 = ExtractPreciseValue<\n        [string, ...boolean[]],\n        ['a', ...unknown[]]\n      >;\n      type t3 = Expect<Equal<res3, ['a', ...boolean[]]>>;\n\n      type res4 = ExtractPreciseValue<\n        (string | boolean)[],\n        ['a', ...unknown[]]\n      >;\n      type t4 = Expect<Equal<res4, ['a', ...(string | boolean)[]]>>;\n    });\n\n    it('[a, b, ...c[]]', () => {\n      type res1 = ExtractPreciseValue<\n        unknown[],\n        [unknown, unknown, ...unknown[]]\n      >;\n      type t1 = Expect<Equal<res1, [unknown, unknown, ...unknown[]]>>;\n\n      type res2 = ExtractPreciseValue<\n        unknown[],\n        [number, boolean, ...string[]]\n      >;\n      type t2 = Expect<Equal<res2, [number, boolean, ...string[]]>>;\n\n      type res3 = ExtractPreciseValue<\n        [string, number, ...boolean[]],\n        ['a', 2, ...unknown[]]\n      >;\n      type t3 = Expect<Equal<res3, ['a', 2, ...boolean[]]>>;\n    });\n\n    it('[...a[], b]', () => {\n      type res1 = ExtractPreciseValue<unknown[], [...unknown[], unknown]>;\n      type t1 = Expect<Equal<res1, [...unknown[], unknown]>>;\n\n      type res2 = ExtractPreciseValue<unknown[], [...string[], number]>;\n      type t2 = Expect<Equal<res2, [...string[], number]>>;\n\n      type res3 = ExtractPreciseValue<\n        [...boolean[], string],\n        [...unknown[], 'a']\n      >;\n      type t3 = Expect<Equal<res3, [...boolean[], 'a']>>;\n    });\n    it('[...a[], b, c]', () => {\n      type res1 = ExtractPreciseValue<\n        unknown[],\n        [...unknown[], unknown, unknown]\n      >;\n      type t1 = Expect<Equal<res1, [...unknown[], unknown, unknown]>>;\n\n      type res2 = ExtractPreciseValue<\n        unknown[],\n        [...string[], number, boolean]\n      >;\n      type t2 = Expect<Equal<res2, [...string[], number, boolean]>>;\n\n      type res3 = ExtractPreciseValue<\n        [...boolean[], string, boolean],\n        [...unknown[], 'a', true]\n      >;\n      type t3 = Expect<Equal<res3, [...boolean[], 'a', true]>>;\n    });\n    it('[a, ...b[], c]', () => {\n      type res1 = ExtractPreciseValue<\n        unknown[],\n        [unknown, ...unknown[], unknown]\n      >;\n      type t1 = Expect<Equal<res1, [unknown, ...unknown[], unknown]>>;\n\n      type res2 = ExtractPreciseValue<\n        unknown[],\n        [number, ...string[], boolean]\n      >;\n      type t2 = Expect<Equal<res2, [number, ...string[], boolean]>>;\n\n      type res3 = ExtractPreciseValue<\n        [string, ...boolean[], number],\n        ['a', ...unknown[], 2]\n      >;\n      type t3 = Expect<Equal<res3, ['a', ...boolean[], 2]>>;\n    });\n  });\n});\n\ndescribe('generics', () => {\n  it(\"shouldn't get stuck on generics in the input structure that aren't matched by the pattern\", () => {\n    const fn = <TResult, TError>() => {\n      type res1 = ExtractPreciseValue<\n        // ^?\n        AsyncResult<TResult, TError>,\n        { status: 'loading' }\n      >;\n\n      type test1 = Expect<\n        Equal<\n          res1,\n          {\n            status: 'loading';\n            data?: TResult | undefined;\n            error?: TError | undefined;\n          }\n        >\n      >;\n    };\n  });\n});\n"
  },
  {
    "path": "tests/find-selected.test.ts",
    "content": "import * as symbols from '../src/internals/symbols';\nimport {\n  FindSelected,\n  MixedNamedAndAnonymousSelectError,\n  SeveralAnonymousSelectError,\n} from '../src/types/FindSelected';\nimport { Equal, Expect } from '../src/types/helpers';\nimport {\n  Matcher,\n  SelectP,\n  NotP,\n  OptionalP,\n  ArrayP,\n} from '../src/types/Pattern';\nimport { Event, State } from './types-catalog/utils';\n\ntype AnonymousSelectP = SelectP<symbols.anonymousSelectKey>;\n\ndescribe('FindSelected', () => {\n  describe('should correctly return kwargs', () => {\n    it('Tuples', () => {\n      type res1 = FindSelected<\n        { a: { b: { c: [3] } } },\n        {\n          a: {\n            b: {\n              c: [SelectP<'c'>];\n            };\n          };\n        }\n      >;\n      type test1 = Expect<Equal<res1, { c: 3 }>>;\n\n      type cases = [\n        Expect<\n          Equal<\n            FindSelected<[State, Event], [SelectP<'state'>, SelectP<'event'>]>,\n            { state: State; event: Event }\n          >\n        >,\n        Expect<\n          Equal<\n            FindSelected<\n              [1, 2, 3],\n              [SelectP<'first'>, SelectP<'second'>, SelectP<'third'>]\n            >,\n            { first: 1; second: 2; third: 3 }\n          >\n        >,\n        Expect<\n          Equal<\n            FindSelected<\n              [1, 2, 3, 4],\n              [SelectP<'1'>, SelectP<'2'>, SelectP<'3'>, SelectP<'4'>]\n            >,\n            { '1': 1; '2': 2; '3': 3; '4': 4 }\n          >\n        >,\n        Expect<\n          Equal<\n            FindSelected<\n              [1, 2, 3, 4, 5],\n              [\n                SelectP<'1'>,\n                SelectP<'2'>,\n                SelectP<'3'>,\n                SelectP<'4'>,\n                SelectP<'5'>\n              ]\n            >,\n            { '1': 1; '2': 2; '3': 3; '4': 4; '5': 5 }\n          >\n        >\n      ];\n    });\n\n    describe('variadic tuples', () => {\n      it('[a, ...b[]]', () => {\n        type res1 = FindSelected<\n          [State, ...Event[]],\n          [SelectP<'state'>, ...ArrayP<unknown, SelectP<'event'>>[]]\n        >;\n        type test1 = Expect<Equal<res1, { state: State; event: Event[] }>>;\n\n        type res2 = FindSelected<\n          [1, ...number[]],\n          [AnonymousSelectP, ...ArrayP<unknown, unknown>[]]\n        >;\n        type test2 = Expect<Equal<res2, 1>>;\n\n        type res3 = FindSelected<\n          [1, ...number[]],\n          [unknown, ...ArrayP<unknown, AnonymousSelectP>[]]\n        >;\n        type test3 = Expect<Equal<res3, number[]>>;\n      });\n\n      it('[a, b, ...c[]]', () => {\n        type res1 = FindSelected<\n          [State, State, ...Event[]],\n          [\n            SelectP<'state'>,\n            SelectP<'state2'>,\n            ...ArrayP<unknown, SelectP<'event'>>[]\n          ]\n        >;\n        type test1 = Expect<\n          Equal<res1, { state: State; state2: State; event: Event[] }>\n        >;\n\n        type res2 = FindSelected<\n          [1, 2, ...number[]],\n          [AnonymousSelectP, unknown, ...ArrayP<unknown, unknown>[]]\n        >;\n        type test2 = Expect<Equal<res2, 1>>;\n\n        type res3 = FindSelected<\n          [1, 2, ...number[]],\n          [unknown, AnonymousSelectP, ...ArrayP<unknown, unknown>[]]\n        >;\n        type test3 = Expect<Equal<res3, 2>>;\n\n        type res4 = FindSelected<\n          [1, 2, ...number[]],\n          [unknown, unknown, ...ArrayP<unknown, AnonymousSelectP>[]]\n        >;\n        type test4 = Expect<Equal<res4, number[]>>;\n      });\n      it('[...a[], b]', () => {\n        type res1 = FindSelected<\n          [...Event[], State],\n          [...ArrayP<unknown, SelectP<'event'>>[], SelectP<'state'>]\n        >;\n        type test1 = Expect<Equal<res1, { state: State; event: Event[] }>>;\n\n        type res2 = FindSelected<\n          [...number[], 1],\n          [...ArrayP<unknown, unknown>[], AnonymousSelectP]\n        >;\n        type test2 = Expect<Equal<res2, 1>>;\n\n        type res3 = FindSelected<\n          [...number[], 1],\n          [...ArrayP<unknown, AnonymousSelectP>[], unknown]\n        >;\n        type test3 = Expect<Equal<res3, number[]>>;\n      });\n      it('[...a[], b, c]', () => {\n        type res1 = FindSelected<\n          [...Event[], State, State],\n          [\n            ...ArrayP<unknown, SelectP<'event'>>[],\n            SelectP<'state'>,\n            SelectP<'state2'>\n          ]\n        >;\n        type test1 = Expect<\n          Equal<res1, { state: State; state2: State; event: Event[] }>\n        >;\n\n        type res2 = FindSelected<\n          [...number[], 1, 2],\n          [...ArrayP<unknown, unknown>[], AnonymousSelectP, unknown]\n        >;\n        type test2 = Expect<Equal<res2, 1>>;\n\n        type res3 = FindSelected<\n          [...number[], 1, 2],\n          [...ArrayP<unknown, unknown>[], unknown, AnonymousSelectP]\n        >;\n        type test3 = Expect<Equal<res3, 2>>;\n\n        type res4 = FindSelected<\n          [...number[], 1, 2],\n          [...ArrayP<unknown, AnonymousSelectP>[], unknown, unknown]\n        >;\n        type test4 = Expect<Equal<res4, number[]>>;\n      });\n\n      it('[a, ...b[], c]', () => {\n        type res1 = FindSelected<\n          [State, ...Event[], State],\n          [\n            SelectP<'state'>,\n            ...ArrayP<unknown, SelectP<'event'>>[],\n            SelectP<'state2'>\n          ]\n        >;\n        type test1 = Expect<\n          Equal<res1, { state: State; state2: State; event: Event[] }>\n        >;\n\n        type res2 = FindSelected<\n          [1, ...number[], 2],\n          [AnonymousSelectP, ...ArrayP<unknown, unknown>[], unknown]\n        >;\n        type test2 = Expect<Equal<res2, 1>>;\n\n        type res3 = FindSelected<\n          [1, ...number[], 2],\n          [unknown, ...ArrayP<unknown, unknown>[], AnonymousSelectP]\n        >;\n        type test3 = Expect<Equal<res3, 2>>;\n\n        type res4 = FindSelected<\n          [1, ...number[], 2],\n          [unknown, ...ArrayP<unknown, AnonymousSelectP>[], unknown]\n        >;\n        type test4 = Expect<Equal<res4, number[]>>;\n      });\n\n      it('[a, b, select(c), ...d[], e]', () => {\n        type res1 = FindSelected<\n          [State, State, number, ...Event[], 1],\n          [1, 2, AnonymousSelectP, ...ArrayP<unknown, 3>[], 4]\n        >;\n        type test1 = Expect<Equal<res1, number>>;\n\n        type res2 = FindSelected<\n          [State, State, Event, ...State[], 1],\n          [1, 2, AnonymousSelectP, ...ArrayP<unknown, 3>[], 4]\n        >;\n        type test2 = Expect<Equal<res2, Event>>;\n      });\n\n      it('[a, ...b[], select(c), d, e]', () => {\n        type res1 = FindSelected<\n          [State, State, State, number, State, State],\n          [1, ...ArrayP<unknown, 3>[], AnonymousSelectP, 4, 2]\n        >;\n        type test1 = Expect<Equal<res1, number>>;\n\n        type res2 = FindSelected<\n          [State, State, State, State, number, State],\n          [1, ...ArrayP<unknown, 3>[], AnonymousSelectP, 4, 2]\n        >;\n        type test2 = Expect<Equal<res2, State>>;\n      });\n    });\n\n    it('list selections should be wrapped in arrays', () => {\n      type cases = [\n        Expect<\n          Equal<\n            FindSelected<State[], ArrayP<unknown, SelectP<'state'>>>,\n            { state: State[] }\n          >\n        >,\n        Expect<\n          Equal<\n            FindSelected<\n              State[][],\n              ArrayP<unknown, ArrayP<unknown, SelectP<'state'>>>\n            >,\n            { state: State[][] }\n          >\n        >,\n        Expect<\n          Equal<\n            FindSelected<\n              State[][][],\n              ArrayP<\n                unknown,\n                ArrayP<unknown, ArrayP<unknown, SelectP<'state'>>>\n              >\n            >,\n            { state: State[][][] }\n          >\n        >\n      ];\n    });\n\n    it('Objects', () => {\n      type cases = [\n        Expect<\n          Equal<\n            FindSelected<\n              { a: { b: { c: 3 } } },\n              { a: { b: { c: SelectP<'c'> } } }\n            >,\n            { c: 3 }\n          >\n        >,\n        Expect<\n          Equal<\n            FindSelected<\n              { a: { b: { c: 3 }; d: { e: 7 } } },\n              {\n                a: {\n                  b: { c: SelectP<'c'> };\n                  d: { e: SelectP<'e'> };\n                };\n              }\n            >,\n            { c: 3; e: 7 }\n          >\n        >\n      ];\n    });\n\n    it('Mixed', () => {\n      type res1 = FindSelected<\n        { a: { b: { c: [3, 4] } } },\n        { a: { b: { c: [SelectP<'c'>, unknown] } } }\n      >;\n\n      type res12 = FindSelected<\n        [{ c: 3 }, { e: 7 }],\n        [{ c: SelectP<'c'> }, { e: 7 }]\n      >;\n\n      type x = Extract<[1, 2], readonly any[]>;\n      type test1 = Expect<Equal<res1, { c: 3 }>>;\n      type res2 = FindSelected<\n        { a: [{ c: 3 }, { e: 7 }]; b: { d: string }[] },\n        {\n          a: [{ c: SelectP<'c'> }, { e: 7 }];\n          b: Matcher<unknown, { d: SelectP<'d'> }, 'array'>;\n        }\n      >;\n      type test2 = Expect<Equal<res2, { c: 3; d: string[] }>>;\n    });\n  });\n\n  describe('Anonymous selections', () => {\n    it('should correctly return a positional argument', () => {\n      type cases = [\n        Expect<\n          Equal<\n            FindSelected<\n              { a: [{ c: 3 }, { e: 7 }]; b: { d: string }[] },\n              {\n                a: [{ c: AnonymousSelectP }, { e: 7 }];\n              }\n            >,\n            3\n          >\n        >\n      ];\n    });\n\n    it('should return an error when trying to use several anonymous select', () => {\n      type cases = [\n        Expect<\n          Equal<\n            FindSelected<\n              { a: [{ c: 3 }, { e: 7 }]; b: { d: string }[] },\n              {\n                a: [{ c: AnonymousSelectP }, { e: AnonymousSelectP }];\n              }\n            >,\n            SeveralAnonymousSelectError\n          >\n        >,\n        Expect<\n          Equal<\n            FindSelected<\n              { a: [{ c: 3 }, { e: 7 }]; b: { d: string }[] },\n              {\n                a: [unknown, { e: AnonymousSelectP }];\n                b: AnonymousSelectP;\n              }\n            >,\n            SeveralAnonymousSelectError\n          >\n        >,\n        Expect<\n          Equal<\n            FindSelected<\n              [{ c: 3 }, { e: 7 }],\n              [{ c: AnonymousSelectP }, { e: AnonymousSelectP }]\n            >,\n            SeveralAnonymousSelectError\n          >\n        >,\n        Expect<\n          Equal<\n            FindSelected<\n              [{ c: 3 }, { e: 7 }],\n              [AnonymousSelectP, { e: AnonymousSelectP }]\n            >,\n            SeveralAnonymousSelectError\n          >\n        >,\n        Expect<\n          Equal<\n            FindSelected<\n              [{ c: 3 }, { e: 7 }],\n              [AnonymousSelectP, AnonymousSelectP]\n            >,\n            SeveralAnonymousSelectError\n          >\n        >,\n        Expect<\n          Equal<\n            FindSelected<\n              { type: 'point'; x: number; y: number },\n              {\n                type: 'point';\n                x: AnonymousSelectP;\n                y: AnonymousSelectP;\n              }\n            >,\n            SeveralAnonymousSelectError\n          >\n        >\n      ];\n    });\n\n    describe('Mix of named and unnamed selections', () => {\n      type Input =\n        | { type: 'text'; text: string; author: { name: string } }\n        | { type: 'video'; duration: number; src: string }\n        | {\n            type: 'movie';\n            duration: number;\n            author: { name: string };\n            src: string;\n            title: string;\n          }\n        | { type: 'picture'; src: string };\n\n      type cases = [\n        Expect<\n          Equal<\n            FindSelected<\n              Input,\n              {\n                type: 'text';\n                text: AnonymousSelectP;\n                author: {\n                  name: SelectP<'authorName'>;\n                };\n              }\n            >,\n            MixedNamedAndAnonymousSelectError\n          >\n        >\n      ];\n    });\n\n    describe('No selection', () => {\n      it('should return the input type', () => {\n        type Input = { type: 'text'; text: string; author: { name: string } };\n\n        type cases = [\n          Expect<Equal<FindSelected<Input, { type: 'text' }>, Input>>,\n          Expect<\n            Equal<FindSelected<{ text: any }, { text: 'text' }>, { text: any }>\n          >,\n          Expect<\n            Equal<\n              FindSelected<\n                { text: any },\n                { str: NotP<null | undefined, null | undefined> }\n              >,\n              { text: any }\n            >\n          >,\n          Expect<\n            Equal<\n              FindSelected<{ text: unknown }, { text: 'text' }>,\n              { text: unknown }\n            >\n          >,\n          Expect<\n            Equal<\n              FindSelected<\n                { text: unknown },\n                { str: NotP<null | undefined, null | undefined> }\n              >,\n              { text: unknown }\n            >\n          >\n        ];\n      });\n\n      it(\"shouldn't change optional properties\", () => {\n        type p = {\n          type: 'a';\n          data: OptionalP<\n            | {\n                type: 'img';\n                src: string;\n              }\n            | {\n                type: 'text';\n                p: string;\n              }\n            | {\n                type: 'video';\n                src: number;\n              }\n            | {\n                type: 'gif';\n                p: string;\n              }\n            | undefined,\n            | {\n                type: 'img';\n              }\n            | undefined\n          >;\n        };\n\n        type value = {\n          type: 'a';\n          data?:\n            | {\n                type: 'img';\n                src: string;\n              }\n            | undefined;\n        };\n\n        type t = Expect<Equal<FindSelected<value, p>, value>>;\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "tests/generics.test.ts",
    "content": "import { match, P } from '../src';\nimport { Equal, Expect } from '../src/types/helpers';\nimport {\n  AsyncResult,\n  AsyncResultError,\n  AsyncResultSuccess,\n  none,\n  Option,\n  some,\n} from './types-catalog/utils';\n\ndescribe('generics', () => {\n  type State<T> =\n    | { t: 'success'; value: T }\n    | { t: 'error'; error: Error }\n    | { t: 'loading' };\n\n  it('should have basic support for objects containing generics', () => {\n    const f = <T>(input: State<T>) => {\n      return match(input)\n        .with({ t: 'success' }, (x) => {\n          type t = Expect<Equal<typeof x, { t: 'success'; value: T }>>;\n          return 'success!';\n        })\n        .with({ t: 'error' }, (x) => {\n          type t = Expect<Equal<typeof x, { t: 'error'; error: Error }>>;\n          return 'error :(';\n        })\n        .with({ t: 'loading' }, (x) => {\n          type t = Expect<Equal<typeof x, { t: 'loading' }>>;\n          return 'loading...';\n        })\n        .exhaustive();\n    };\n  });\n\n  it('should have basic support for arrays containing generics', () => {\n    const last = <a>(xs: a[]) =>\n      match<a[], Option<a>>(xs)\n        .with([], () => none)\n        .with(P._, (x, y) => {\n          type t = Expect<Equal<typeof x, a[]>>;\n          type t2 = Expect<Equal<typeof y, a[]>>;\n          return some(xs[xs.length - 1]);\n        })\n        .exhaustive();\n  });\n\n  it('should have basic support for tuples containing generics', () => {\n    type State<T> = { t: 'success'; value: T } | { t: 'error'; error: Error };\n\n    const f = <a, b>(xs: [State<a>, State<b>]) =>\n      match(xs)\n        .with([{ t: 'success' }, { t: 'success' }], ([x, y]) => {\n          type t = Expect<Equal<typeof x, { t: 'success'; value: a }>>;\n          type t2 = Expect<Equal<typeof y, { t: 'success'; value: b }>>;\n          return 'success!';\n        })\n        .with([{ t: 'success' }, { t: 'error' }], ([x, y]) => {\n          type t = Expect<Equal<typeof x, { t: 'success'; value: a }>>;\n          type t2 = Expect<Equal<typeof y, { t: 'error'; error: Error }>>;\n          return 'success!';\n        })\n        .with([{ t: 'error' }, P._], ([x, y]) => {\n          type t = Expect<Equal<typeof x, { t: 'error'; error: Error }>>;\n          type t2 = Expect<Equal<typeof y, State<b>>>;\n          return 'error :(';\n        })\n        .exhaustive();\n  });\n\n  it('Basic generic type guards (with no type level manipulation of the input) should work', () => {\n    const isSuccess = <T>(x: any): x is { t: 'success'; value: T } =>\n      Boolean(x && typeof x === 'object' && x.t === 'success');\n\n    const isDoubleSuccess = <T>(x: any): x is { t: 'success'; value: [T, T] } =>\n      Boolean(\n        x &&\n          typeof x === 'object' &&\n          x.t === 'success' &&\n          Array.isArray(x.value) &&\n          x.value.length === 2\n      );\n\n    const f = <T>(input: State<[number, number] | number>) => {\n      return match({ input })\n        .with({ input: P.when(isSuccess) }, (x) => {\n          type t = Expect<\n            Equal<\n              typeof x,\n              { input: { t: 'success'; value: number | [number, number] } }\n            >\n          >;\n          return 'ok';\n        })\n        .with({ input: P.when(isDoubleSuccess) }, (x) => {\n          type t = Expect<\n            Equal<\n              typeof x,\n              { input: { t: 'success'; value: [number, number] } }\n            >\n          >;\n          return 'ok';\n        })\n        .otherwise(() => 'nope');\n    };\n  });\n\n  it(\"shouldn't get stucked on type parameters if they aren't included in the pattern\", () => {\n    const fn = <TResult, TError>(result: AsyncResult<TResult, TError>) => {\n      return match(result)\n        .with({ status: 'success' }, (x) => {\n          type test = Expect<\n            Equal<typeof x, AsyncResultSuccess<TResult, TError>>\n          >;\n        })\n        .with({ status: 'error' }, (x) => {\n          type test = Expect<\n            Equal<typeof x, AsyncResultError<TResult, TError>>\n          >;\n        })\n        .with({ status: 'loading' }, (x) => {\n          type test = Expect<\n            Equal<\n              typeof x,\n              {\n                status: 'loading';\n                error?: TError | undefined;\n                data?: TResult | undefined;\n              }\n            >\n          >;\n        })\n        .with({ status: 'idle' }, (x) => {\n          type test = Expect<\n            Equal<\n              typeof x,\n              {\n                status: 'idle';\n                error?: TError | undefined;\n                data?: TResult | undefined;\n              }\n            >\n          >;\n        })\n        .exhaustive();\n    };\n  });\n});\n"
  },
  {
    "path": "tests/helpers.test.ts",
    "content": "import {\n  Drop,\n  Equal,\n  Expect,\n  Iterator,\n  LeastUpperBound,\n  Take,\n  IntersectObjects,\n  UpdateAt,\n  IsReadonlyArray,\n} from '../src/types/helpers';\n\ndescribe('helpers', () => {\n  describe('Take', () => {\n    it('should correctly return the start of a tuple', () => {\n      type cases = [\n        Expect<Equal<Take<[1, 2, 3], Iterator<0>>, []>>,\n        Expect<Equal<Take<[1, 2, 3], Iterator<1>>, [1]>>,\n        Expect<Equal<Take<[1, 2, 3], Iterator<2>>, [1, 2]>>,\n        Expect<Equal<Take<[1, 2, 3], Iterator<3>>, [1, 2, 3]>>,\n        Expect<Equal<Take<[1, 2, 3], Iterator<4>>, [1, 2, 3]>>\n      ];\n    });\n\n    it('should correctly return the start of a readonly tuple', () => {\n      type cases = [\n        Expect<Equal<Take<readonly [1, 2, 3], Iterator<0>>, []>>,\n        Expect<Equal<Take<readonly [1, 2, 3], Iterator<1>>, [1]>>,\n        Expect<Equal<Take<readonly [1, 2, 3], Iterator<2>>, [1, 2]>>,\n        Expect<Equal<Take<readonly [1, 2, 3], Iterator<3>>, [1, 2, 3]>>,\n        Expect<Equal<Take<readonly [1, 2, 3], Iterator<4>>, [1, 2, 3]>>\n      ];\n    });\n  });\n\n  describe('Drop', () => {\n    it('should correctly remove the n first elements of a tuple', () => {\n      type cases = [\n        Expect<Equal<Drop<[1, 2, 3], Iterator<0>>, [1, 2, 3]>>,\n        Expect<Equal<Drop<[1, 2, 3], Iterator<1>>, [2, 3]>>,\n        Expect<Equal<Drop<[1, 2, 3], Iterator<2>>, [3]>>,\n        Expect<Equal<Drop<[1, 2, 3], Iterator<3>>, []>>,\n        Expect<Equal<Drop<[1, 2, 3], Iterator<4>>, []>>\n      ];\n    });\n\n    it('should correctly remove the n first elements of a readonly tuple', () => {\n      type cases = [\n        Expect<\n          Equal<Drop<readonly [1, 2, 3], Iterator<0>>, readonly [1, 2, 3]>\n        >,\n        Expect<Equal<Drop<readonly [1, 2, 3], Iterator<1>>, [2, 3]>>,\n        Expect<Equal<Drop<readonly [1, 2, 3], Iterator<2>>, [3]>>,\n        Expect<Equal<Drop<readonly [1, 2, 3], Iterator<3>>, []>>,\n        Expect<Equal<Drop<readonly [1, 2, 3], Iterator<4>>, []>>\n      ];\n    });\n  });\n\n  describe('UpdateAt', () => {\n    type cases = [\n      Expect<\n        Equal<UpdateAt<readonly [1, 2, 3], Iterator<0>, true>, [true, 2, 3]>\n      >,\n      Expect<\n        Equal<UpdateAt<readonly [1, 2, 3], Iterator<1>, true>, [1, true, 3]>\n      >,\n      Expect<\n        Equal<UpdateAt<readonly [1, 2, 3], Iterator<2>, true>, [1, 2, true]>\n      >,\n      Expect<Equal<UpdateAt<readonly [1, 2, 3], Iterator<3>, true>, [1, 2, 3]>>,\n      Expect<Equal<UpdateAt<readonly [1, 2, 3], Iterator<4>, true>, [1, 2, 3]>>\n    ];\n  });\n\n  describe('LeastUpperBound', () => {\n    it('If both a and b extend each other, it should pick b', () => {\n      class B {}\n      class A extends B {}\n      type t = Expect<Equal<LeastUpperBound<A | B, B>, B>>;\n    });\n  });\n\n  describe('IntersectObjects', () => {\n    it('', () => {\n      type x = IntersectObjects<\n        | { k: 'a'; value: number; a: string }\n        | { k: 'b'; value: string; b: string }\n        | { k: 'c'; value: number; c: string }\n      >;\n\n      type t = Expect<\n        Equal<\n          x,\n          {\n            k: 'a' | 'b' | 'c';\n            value: number | string;\n            a: string;\n            b: string;\n            c: string;\n          }\n        >\n      >;\n\n      type t2 = Expect<\n        Equal<\n          IntersectObjects<\n            | { k: 'a'; value: number }\n            | { k: 'b'; value: string }\n            | { k: 'c'; value: number }\n          >,\n          {\n            k: 'a' | 'b' | 'c';\n            value: number | string;\n          }\n        >\n      >;\n\n      type t3 = Expect<\n        Equal<\n          IntersectObjects<\n            | { type: 1; data: number }\n            | { type: 'two'; data: string }\n            | { type: 3; data: boolean }\n            | { type: 4 }\n          >,\n          { type: 1 | 'two' | 3 | 4; data: number | string | boolean }\n        >\n      >;\n    });\n  });\n\n  describe('IsReadonlyArray', () => {\n    type t1 = IsReadonlyArray<readonly []>;\n    type test1 = Expect<Equal<t1, true>>;\n    type t2 = IsReadonlyArray<readonly number[]>;\n    type test2 = Expect<Equal<t2, true>>;\n    type t3 = IsReadonlyArray<readonly [number]>;\n    type test3 = Expect<Equal<t3, true>>;\n    type t4 = IsReadonlyArray<readonly [number, ...(readonly any[])]>;\n    type test4 = Expect<Equal<t4, true>>;\n    type t5 = IsReadonlyArray<readonly [...(readonly any[]), number]>;\n    type test5 = Expect<Equal<t5, true>>;\n\n    type t6 = IsReadonlyArray<[]>;\n    type test6 = Expect<Equal<t6, false>>;\n    type t7 = IsReadonlyArray<number[]>;\n    type test7 = Expect<Equal<t7, false>>;\n    type t8 = IsReadonlyArray<[number]>;\n    type test8 = Expect<Equal<t8, false>>;\n    type t9 = IsReadonlyArray<[number, ...any[]]>;\n    type test9 = Expect<Equal<t9, false>>;\n    type t10 = IsReadonlyArray<[...any[], number]>;\n    type test10 = Expect<Equal<t10, false>>;\n  });\n});\n"
  },
  {
    "path": "tests/infer.test.ts",
    "content": "import { P } from '../src';\nimport { Equal, Expect } from '../src/types/helpers';\n\ndescribe('P.infer', () => {\n  describe('array', () => {\n    it('should correctly narrow types of arrays containing tuples', () => {\n      const QuizValue = P.union('initial', 'correct', 'incorrect');\n      const QuizState = {\n        answerEntries: P.array([P.string, QuizValue]),\n        appendOnlyAnswerEntries: P.array([P.string, P.array(QuizValue)]),\n      };\n\n      type QuizValue = P.infer<typeof QuizValue>;\n      type expected1 = 'initial' | 'correct' | 'incorrect';\n      type test1 = Expect<Equal<QuizValue, expected1>>;\n\n      type QuizState = P.infer<typeof QuizState>;\n      type expected2 = {\n        answerEntries: [string, QuizValue][];\n        appendOnlyAnswerEntries: [string, QuizValue[]][];\n      };\n      type test2 = Expect<Equal<QuizState, expected2>>;\n    });\n  });\n\n  it(\"P.infer shouldn't count as an inference point of the pattern\", () => {\n    const getValueOfType = <T extends P.Pattern<unknown>>(\n      obj: unknown,\n      path: string,\n      pattern: T,\n      defaultValue: P.infer<T>\n    ): P.infer<T> => defaultValue;\n\n    getValueOfType(\n      null,\n      'a.b.c',\n      { x: P.string },\n      // @ts-expect-error 👇 error should be here\n      'oops'\n    );\n  });\n});\n"
  },
  {
    "path": "tests/instance-of.test.ts",
    "content": "import { Expect, Equal } from '../src/types/helpers';\nimport { match, P } from '../src';\n\nclass A {\n  a = 'a';\n}\nclass B {\n  b = 'b';\n}\n\ndescribe('instanceOf', () => {\n  it('should work at the top level', () => {\n    const get = (x: A | B): string =>\n      match(x)\n        .with(P.instanceOf(A), (x) => {\n          type t = Expect<Equal<typeof x, A>>;\n          return 'instance of A';\n        })\n        .with(P.instanceOf(B), (x) => {\n          type t = Expect<Equal<typeof x, B>>;\n          return 'instance of B';\n        })\n        .exhaustive();\n\n    expect(get(new A())).toEqual('instance of A');\n    expect(get(new B())).toEqual('instance of B');\n  });\n\n  it('should work as a nested pattern', () => {\n    type Input = { value: A | B };\n\n    const input = { value: new A() };\n\n    const output = match<Input>(input)\n      .with({ value: P.instanceOf(A) }, (a) => {\n        type t = Expect<Equal<typeof a, { value: A }>>;\n        return 'instance of A!';\n      })\n      .with({ value: P.instanceOf(B) }, (b) => {\n        type t = Expect<Equal<typeof b, { value: B }>>;\n        return 'instance of B!';\n      })\n      .exhaustive();\n\n    expect(output).toEqual('instance of A!');\n  });\n\n  it('issue #63: should work on union of errors', () => {\n    class FooError extends Error {\n      constructor(public foo: string) {\n        super();\n      }\n    }\n\n    class BazError extends Error {\n      constructor(public baz: string) {\n        super();\n      }\n    }\n\n    type Input = FooError | BazError | Error;\n\n    let err: Input = new FooError('foo');\n\n    expect(\n      match<Input, string | undefined>(err)\n        .with(P.instanceOf(FooError), (err) => err.foo)\n        .with(P.instanceOf(BazError), (err) => err.baz)\n        .otherwise(() => 'nothing')\n    ).toBe('foo');\n  });\n\n  it('should work with abstract classes', () => {\n    abstract class Abstract {}\n\n    class A extends Abstract {}\n    class B extends Abstract {}\n\n    const get = (x: A | B): string =>\n      match(x)\n        .with(P.instanceOf(Abstract), (x) => {\n          type t = Expect<Equal<typeof x, A | B>>;\n          return 'instance of Abstract';\n        })\n        .exhaustive();\n\n    expect(get(new A())).toEqual('instance of Abstract');\n    expect(get(new B())).toEqual('instance of Abstract');\n  });\n});\n"
  },
  {
    "path": "tests/intersection-and-union.test.ts",
    "content": "import { match, P } from '../src';\nimport { Equal, Expect } from '../src/types/helpers';\n\ndescribe('and, and or patterns', () => {\n  type A = {\n    type: 'a';\n    value: [\n      { type: 'd'; value: number } | { type: 'e'; value: string },\n      boolean\n    ];\n  };\n\n  type B = {\n    type: 'b';\n    data: {\n      some?: 'thing' | 'stuff' | '?';\n    };\n    children: Input[];\n  };\n\n  type Input = A | B;\n\n  abstract class Parent {}\n\n  class Child1 extends Parent {\n    constructor(public a?: Parent, public b?: Parent) {\n      super();\n    }\n  }\n\n  class Child2 extends Parent {\n    constructor(public a?: Parent, public b?: Parent) {\n      super();\n    }\n  }\n\n  describe('or', () => {\n    it('should match if one of the patterns matches', () => {\n      const f = (input: Input) =>\n        match(input)\n          .with(\n            P.union(\n              { type: 'a', value: [{ type: 'd' }, true] } as const,\n              {\n                type: 'b',\n              } as const\n            ),\n            (x) => {\n              type t = Expect<\n                Equal<\n                  typeof x,\n                  | B\n                  | {\n                      type: 'a';\n                      value: [{ type: 'd'; value: number }, true];\n                    }\n                >\n              >;\n              return 'branch 3';\n            }\n          )\n          .with(\n            {\n              type: 'a',\n              value: [P.union({ type: 'd' }, { type: 'e' }), true],\n            },\n            (x) => {\n              type t = Expect<\n                Equal<\n                  typeof x,\n                  {\n                    type: 'a';\n                    value: [\n                      (\n                        | { type: 'd'; value: number }\n                        | { type: 'e'; value: string }\n                      ),\n                      true\n                    ];\n                  }\n                >\n              >;\n              return 'branch 1';\n            }\n          )\n          .with({ type: 'a' }, (x) => {\n            type t = Expect<Equal<typeof x, A>>;\n            return 'branch 2';\n          })\n\n          .exhaustive();\n    });\n\n    it('unions and intersections should work on properties shared by several element in a union type', () => {\n      type C = {\n        type: 'c';\n        value:\n          | { type: 'd'; value: boolean }\n          | { type: 'e'; value: string[] }\n          | { type: 'f'; value: number[] };\n      };\n\n      type Input =\n        | { type: 'a'; value: string }\n        | { type: 'b'; value: number }\n        | C;\n\n      const f = (input: Input) =>\n        match(input)\n          .with({ type: P.union('a', 'b') }, (x) => {\n            type t = Expect<\n              Equal<\n                typeof x,\n                { type: 'a'; value: string } | { type: 'b'; value: number }\n              >\n            >;\n            return 'branch 1';\n          })\n          .with({ type: 'c' }, (x) => {\n            type t = Expect<Equal<typeof x, C>>;\n            return 'branch 2';\n          })\n          .exhaustive();\n\n      const fe = (input: Input) =>\n        match(input)\n          .with({ type: P.union('a', 'b') }, (x) => {\n            type t = Expect<\n              Equal<\n                typeof x,\n                { type: 'a'; value: string } | { type: 'b'; value: number }\n              >\n            >;\n            return 'branch 1';\n          })\n          .with({ type: 'c', value: { type: P.union('d', 'e') } }, (x) => {\n            type t = Expect<\n              Equal<\n                typeof x,\n                {\n                  type: 'c';\n                  value:\n                    | { type: 'd'; value: boolean }\n                    | { type: 'e'; value: string[] };\n                }\n              >\n            >;\n            return 'branch 2';\n          })\n          .with({ type: 'c', value: { type: 'f' } }, (x) => {\n            type t = Expect<\n              Equal<\n                typeof x,\n                {\n                  type: 'c';\n                  value: { type: 'f'; value: number[] };\n                }\n              >\n            >;\n            return 'branch 2';\n          })\n          .exhaustive();\n    });\n\n    it('should work on any depth', () => {\n      type Country = 'France' | 'Germany' | 'Spain' | 'USA';\n\n      const input = { country: 'France' } as { country: Country };\n\n      match(input)\n        .with(\n          { country: P.union('France', 'Germany', 'Spain') },\n          (x) => 'Europe'\n        )\n        .with({ country: 'USA' }, () => 'America')\n        .exhaustive();\n    });\n  });\n\n  describe('and', () => {\n    it('should match if all patterns match', () => {\n      const f = (n: Parent) =>\n        match(n)\n          .with(\n            P.intersection(P.instanceOf(Child1), {\n              a: P.instanceOf(Child2),\n              b: P.instanceOf(Child2),\n            }),\n            (x) => {\n              type t = Expect<\n                Equal<typeof x, Child1 & { a: Child2; b: Child2 }>\n              >;\n              return 'match!';\n            }\n          )\n          .with(P.union(P.instanceOf(Child1), P.instanceOf(Child2)), (x) => {\n            return 'catchall';\n          })\n          .exhaustive();\n\n      expect(f(new Child1(new Child2(), new Child2()))).toBe('match!');\n      expect(f(new Child1(new Child1(), new Child2()))).toBe('catchall');\n    });\n\n    it('should consider two incompatible patterns as matching never', () => {\n      const f = (n: number | string) => {\n        return (\n          match(n)\n            .with(P.intersection(P.number, P.nullish), (x) => {\n              return 'never';\n            })\n            .with(P.string, () => 'string')\n            // @ts-expect-error NonExhaustiveError<number>\n            .exhaustive()\n        );\n      };\n      expect(() => f(20)).toThrow();\n    });\n  });\n\n  describe('composition', () => {\n    it('or and and should nest nicely', () => {\n      const f = (n: Parent) =>\n        match(n)\n          .with(\n            P.instanceOf(Child1).and({\n              a: P.instanceOf(Child2).optional(),\n              b: P.instanceOf(Child2),\n            }),\n            (x) => {\n              type t = Expect<\n                Equal<typeof x, Child1 & { b: Child2; a?: Child2 | undefined }>\n              >;\n              return 'match!';\n            }\n          )\n          .with(\n            P.shape({ a: P.instanceOf(Child1) }).and(\n              P.shape({\n                a: { a: P.instanceOf(Child1), b: P.instanceOf(Child1) },\n              }).or({ b: { a: P.instanceOf(Child2), b: P.instanceOf(Child2) } })\n            ),\n            (x) => {\n              type t = Expect<\n                Equal<\n                  typeof x,\n                  { a: Child1 } & (\n                    | { a: { a: Child1; b: Child1 } }\n                    | { b: { a: Child2; b: Child2 } }\n                  )\n                >\n              >;\n              return 'branch 2';\n            }\n          )\n          .with(P.union(P.instanceOf(Child1), P.instanceOf(Child2)), () => {\n            return 'catchall';\n          })\n          .exhaustive();\n\n      expect(f(new Child1(new Child2(), new Child2()))).toBe('match!');\n      expect(f(new Child1(new Child1(), new Child2()))).toBe('catchall');\n    });\n\n    it(\"using a and patterns with when shouldn't consider the pattern exhaustive unless the guard function truly matches every possibilities of the input\", () => {\n      const f = (n: number) => {\n        return (\n          match(n)\n            .with(\n              P.intersection(\n                P.number,\n                P.when((n): n is never => typeof n === 'number' && n > 20)\n              ),\n              (x) => {\n                return 'big number';\n              }\n            )\n            // @ts-expect-error\n            .exhaustive()\n        );\n      };\n\n      const f2 = (n: number | string) => {\n        return match(n)\n          .with(\n            P.intersection(\n              P.any,\n              P.any,\n              P.when((n): n is number => typeof n === 'number'),\n              P.any,\n              P.select()\n            ),\n            (x) => {\n              type t = Expect<Equal<typeof x, number>>;\n              return 'big number';\n            }\n          )\n          .with(P.string, () => 'string')\n          .exhaustive();\n      };\n\n      const f3 = (n: number | string) => {\n        return (\n          match(n)\n            .with(\n              P.intersection(\n                P.any,\n                P.any,\n                P.when((n): n is number => typeof n === 'number'),\n                P.any,\n                P.select()\n              ),\n              (x) => {\n                type t = Expect<Equal<typeof x, number>>;\n                return 'big number';\n              }\n            )\n            // @ts-expect-error: string isn't handled\n            .exhaustive()\n        );\n      };\n    });\n\n    it('intersection should work with selects', () => {\n      const f = (n: number | string) => {\n        return match({ n })\n          .with(\n            {\n              n: P.intersection(\n                P.any,\n                P.when((n): n is number => typeof n === 'number'),\n                P.any,\n                P.select()\n              ),\n            },\n            (x) => {\n              type t = Expect<Equal<typeof x, number>>;\n              return x;\n            }\n          )\n          .with({ n: P.string }, () => 'string')\n          .exhaustive();\n      };\n\n      expect(f(20)).toEqual(20);\n      expect(f('20')).toEqual('string');\n    });\n\n    it('union & intersections should work with selects', () => {\n      type Input = {\n        value:\n          | { type: 'a'; v: number }\n          | { type: 'b'; v: string }\n          | { type: 'c'; v: boolean };\n      };\n      const f = (input: Input) => {\n        return match(input)\n          .with(\n            {\n              value: P.intersection(\n                P.select(),\n                P.union({ type: 'a' }, { type: 'b' })\n              ),\n            },\n            (x) => {\n              type t = Expect<\n                Equal<\n                  typeof x,\n                  { type: 'a'; v: number } | { type: 'b'; v: string }\n                >\n              >;\n              return x.type;\n            }\n          )\n          .with({ value: { type: 'c' } }, () => 'other')\n          .exhaustive();\n      };\n\n      expect(f({ value: { type: 'a', v: 20 } })).toEqual('a');\n      expect(f({ value: { type: 'c', v: true } })).toEqual('other');\n    });\n\n    it('unions containing selects should consider all selections optional', () => {\n      type Input = {\n        value:\n          | { type: 'a'; n: number }\n          | { type: 'b'; s: string }\n          | { type: 'c'; b: boolean };\n      };\n      const f = (input: Input) => {\n        return match(input)\n          .with(\n            {\n              value: P.union(\n                { type: 'a', n: P.select('n') },\n                { type: 'b', s: P.select('s') }\n              ),\n            },\n            (x) => {\n              type t = Expect<\n                Equal<\n                  typeof x,\n                  {\n                    n: number | undefined;\n                    s: string | undefined;\n                  }\n                >\n              >;\n              return x;\n            }\n          )\n          .with(\n            {\n              value: P.union({ type: 'a', n: P.select() }, { type: 'b' }),\n            },\n            (x) => {\n              type t = Expect<Equal<typeof x, number | undefined>>;\n              return x;\n            }\n          )\n\n          .with({ value: { type: 'c' } }, () => 'other')\n          .exhaustive();\n      };\n\n      expect(f({ value: { type: 'a', n: 20 } })).toEqual({\n        n: 20,\n        s: undefined,\n      });\n      expect(f({ value: { type: 'b', s: 'str' } })).toEqual({\n        a: undefined,\n        s: 'str',\n      });\n      expect(f({ value: { type: 'c', b: true } })).toEqual('other');\n    });\n\n    it('P.not should work with unions and intersections', () => {\n      type Input = {\n        value:\n          | { type: 'a'; n: number }\n          | { type: 'b'; s: string }\n          | { type: 'c'; b: boolean };\n      };\n      const f = (input: Input) => {\n        return match(input)\n          .with({ value: P.not({ type: P.union('a', 'b') }) }, (x) => {\n            type t = Expect<\n              Equal<typeof x, { value: { type: 'c'; b: boolean } }>\n            >;\n            return 'not a or b';\n          })\n          .with({ value: P.union({ type: 'a' }, { type: 'b' }) }, (x) => {\n            type t = Expect<\n              Equal<\n                typeof x,\n                { value: { type: 'a'; n: number } | { type: 'b'; s: string } }\n              >\n            >;\n            return 'a or b';\n          })\n          .exhaustive();\n      };\n\n      expect(f({ value: { type: 'b', s: 'str' } })).toEqual('a or b');\n      expect(f({ value: { type: 'c', b: true } })).toEqual('not a or b');\n    });\n\n    it('P.array should work with unions and intersections', () => {\n      type Input = {\n        value: (\n          | { type: 'a'; n: number }\n          | { type: 'b'; s: string }\n          | { type: 'c'; b: boolean }\n        )[];\n      };\n      const f = (input: Input) => {\n        return match(input)\n          .with({ value: P.array({ type: P.union('a', 'b') }) }, (x) => {\n            type t = Expect<\n              Equal<\n                typeof x,\n                {\n                  value: (\n                    | { type: 'a'; n: number }\n                    | { type: 'b'; s: string }\n                  )[];\n                }\n              >\n            >;\n            return x.value.map((x) => x.type).join(',');\n          })\n          .with(\n            { value: P.array(P.union({ type: 'a' }, { type: 'b' })) },\n            (x) => {\n              type t = Expect<\n                Equal<\n                  typeof x,\n                  {\n                    value: (\n                      | { type: 'a'; n: number }\n                      | { type: 'b'; s: string }\n                    )[];\n                  }\n                >\n              >;\n              return x.value.map((x) => x.type).join(',');\n            }\n          )\n          .with({ value: P.array(P.any) }, () => 'other')\n          .exhaustive();\n      };\n\n      expect(\n        f({\n          value: [\n            { type: 'b', s: 'str' },\n            { type: 'a', n: 2 },\n          ],\n        })\n      ).toEqual('b,a');\n      expect(\n        f({\n          value: [\n            { type: 'a', n: 2 },\n            { type: 'c', b: true },\n          ],\n        })\n      ).toEqual('other');\n    });\n\n    it('Composing P.union and P.array should work on union of arrays', () => {\n      type Input = {\n        value:\n          | { type: 'a'; n: number }[]\n          | { type: 'b'; s: string }[]\n          | { type: 'c'; b: boolean }[];\n      };\n\n      const f = (input: Input) => {\n        return match(input)\n          .with({ value: P.array({ type: P.union('a', 'b') }) }, (x) => {\n            type t = Expect<\n              Equal<\n                typeof x,\n                {\n                  value:\n                    | { type: 'a'; n: number }[]\n                    | { type: 'b'; s: string }[];\n                }\n              >\n            >;\n            return x.value[0].type;\n          })\n          .with(\n            { value: P.array(P.union({ type: 'a' }, { type: 'b' })) },\n            (x) => {\n              type t = Expect<\n                Equal<\n                  typeof x,\n                  {\n                    value:\n                      | { type: 'a'; n: number }[]\n                      | { type: 'b'; s: string }[];\n                  }\n                >\n              >;\n              return x.value[0].type;\n            }\n          )\n          .with({ value: P.array(P.any) }, () => 'other')\n          .exhaustive();\n      };\n\n      expect(\n        f({\n          value: [\n            { type: 'b', s: 'str' },\n            { type: 'b', s: '2' },\n          ],\n        })\n      ).toEqual('b');\n      expect(\n        f({\n          value: [\n            { type: 'a', n: 2 },\n            { type: 'a', n: 3 },\n          ],\n        })\n      ).toEqual('a');\n    });\n\n    it('Composing P.union and P.array should work on union of objects containing arrays', () => {\n      type Input =\n        | {\n            value: { type: 'a'; n: number }[];\n          }\n        | {\n            value: { type: 'b'; s: string }[];\n          }\n        | {\n            value: { type: 'c'; b: boolean }[];\n          };\n\n      const errorF = (input: Input) =>\n        match(input)\n          .with({ value: P.array({ type: P.union('a', 'b', 'c') }) }, (x) => {})\n          .exhaustive();\n\n      const f = (input: Input) => {\n        return match(input)\n          .with(\n            { value: P.array(P.union({ type: 'a' }, { type: 'b' })) },\n            (x) => {\n              type t = Expect<\n                Equal<\n                  typeof x,\n                  | {\n                      value: {\n                        type: 'a';\n                        n: number;\n                      }[];\n                    }\n                  | {\n                      value: {\n                        type: 'b';\n                        s: string;\n                      }[];\n                    }\n                >\n              >;\n              return x.value[0].type;\n            }\n          )\n          .with(\n            {\n              value: P.array({ type: 'c' }),\n            },\n            (x) => {\n              type t = Expect<\n                Equal<\n                  typeof x,\n                  {\n                    value: { type: 'c'; b: boolean }[];\n                  }\n                >\n              >;\n              return x.value[0].type;\n            }\n          )\n          .exhaustive();\n      };\n\n      expect(\n        f({\n          value: [\n            { type: 'b', s: 'str' },\n            { type: 'b', s: '2' },\n          ],\n        })\n      ).toEqual('b');\n      expect(\n        f({\n          value: [\n            { type: 'a', n: 2 },\n            { type: 'a', n: 3 },\n          ],\n        })\n      ).toEqual('a');\n    });\n\n    it('P.optional should work with unions and intersections', () => {\n      type Input = {\n        value?:\n          | { type: 'a'; n: number }\n          | { type: 'b'; s: string }\n          | { type: 'c'; b: boolean };\n      };\n      const f = (input: Input) => {\n        return match(input)\n          .with(\n            { value: P.optional(P.union({ type: 'a' }, { type: 'b' })) },\n            (x) => {\n              type t = Expect<\n                Equal<\n                  typeof x,\n                  {\n                    value?:\n                      | { type: 'a'; n: number }\n                      | { type: 'b'; s: string }\n                      | undefined;\n                  }\n                >\n              >;\n              return 'maybe a or b';\n            }\n          )\n          .with({ value: { type: 'c' } }, (x) => {\n            type t = Expect<\n              Equal<typeof x, { value: { type: 'c'; b: boolean } }>\n            >;\n            return 'c';\n          })\n          .exhaustive();\n      };\n\n      expect(f({ value: { type: 'a', n: 20 } })).toEqual('maybe a or b');\n      expect(f({ value: { type: 'b', s: 'str' } })).toEqual('maybe a or b');\n      expect(f({})).toEqual('maybe a or b');\n      expect(f({ value: { type: 'c', b: true } })).toEqual('c');\n    });\n  });\n\n  it('unknown input', () => {\n    match<unknown>({})\n      .with(\n        // It would be nice if as const wasn't necessary with unknown inputs\n        { a: P.optional(P.union('hello' as const, 'bonjour' as const)) },\n        (x) => {\n          type t = Expect<\n            Equal<typeof x, { a?: 'hello' | 'bonjour' | undefined }>\n          >;\n          return 'ok';\n        }\n      )\n      .otherwise(() => 'ko');\n  });\n\n  it('Inference should work at the top level', () => {\n    class A {\n      constructor(public foo: 'bar' | 'baz') {}\n    }\n\n    class B {\n      constructor(public str: string) {}\n    }\n\n    const f = (input: A | B) =>\n      match(input)\n        .with(\n          P.intersection(P.instanceOf(A), { foo: 'bar' }),\n          // prop: A & { foo: 'bar' }\n          (prop) => {\n            type t = Expect<Equal<typeof prop, A & { foo: 'bar' }>>;\n            return 'branch 1';\n          }\n        )\n        .with(\n          P.intersection(P.instanceOf(A), { foo: 'baz' }),\n          // prop: A & { foo: 'baz' }\n          (prop) => {\n            type t = Expect<Equal<typeof prop, A & { foo: 'baz' }>>;\n            return 'branch 2';\n          }\n        )\n        .with(\n          P.instanceOf(B),\n          // prop: B\n          (prop) => {\n            type t = Expect<Equal<typeof prop, B>>;\n            return 'branch 3';\n          }\n        )\n        .exhaustive();\n  });\n});\n"
  },
  {
    "path": "tests/invert-pattern.test.ts",
    "content": "import { Equal, Expect } from '../src/types/helpers';\nimport {\n  InvertPattern,\n  InvertPatternForExclude,\n} from '../src/types/InvertPattern';\nimport { ArrayP, GuardP, Matcher, Pattern } from '../src/types/Pattern';\n\ndescribe('InvertPattern', () => {\n  describe('variadic tuples', () => {\n    it('[a, ...b[]]', () => {\n      type pattern1 = [\n        'Hello',\n        ...Matcher<any, GuardP<unknown, number>, 'array'>[]\n      ];\n      type inverted1 = InvertPattern<pattern1, unknown>;\n      //    ^?\n      type test1 = Expect<Equal<inverted1, ['Hello', ...number[]]>>;\n\n      type pattern2 = [\n        GuardP<unknown, unknown>,\n        ...Matcher<unknown, unknown, 'array'>[]\n      ];\n      type inverted2 = InvertPattern<pattern2, unknown>;\n      //    ^?\n      type test2 = Expect<Equal<inverted2, [unknown, ...unknown[]]>>;\n\n      type pattern3 = [\n        GuardP<unknown, string>,\n        ...Matcher<any, GuardP<unknown, number>, 'array'>[]\n      ];\n      type inverted3 = InvertPattern<pattern3, unknown>;\n      //    ^?\n      type test3 = Expect<Equal<inverted3, [string, ...number[]]>>;\n\n      type pattern6 = {\n        key: readonly [\n          GuardP<unknown, string>,\n          ...ArrayP<unknown, GuardP<unknown, string>>[]\n        ];\n      };\n      type input6 = unknown;\n      type inverted6 = InvertPattern<pattern6, input6>;\n      //   ^?\n      type test6 = Expect<Equal<inverted6, { key: [string, ...string[]] }>>;\n    });\n\n    it('[a, b, ...c[]]', () => {\n      type pattern1 = [\n        'Hello',\n        7,\n        ...Matcher<any, GuardP<unknown, number>, 'array'>[]\n      ];\n      type inverted1 = InvertPattern<pattern1, unknown>;\n      //    ^?\n      type test1 = Expect<Equal<inverted1, ['Hello', 7, ...number[]]>>;\n\n      type pattern2 = [\n        GuardP<unknown, unknown>,\n        GuardP<unknown, unknown>,\n        ...Matcher<unknown, unknown, 'array'>[]\n      ];\n      type inverted2 = InvertPattern<pattern2, unknown>;\n      //    ^?\n      type test2 = Expect<Equal<inverted2, [unknown, unknown, ...unknown[]]>>;\n\n      type pattern3 = [\n        GuardP<unknown, string>,\n        GuardP<unknown, boolean>,\n        ...Matcher<any, GuardP<unknown, number>, 'array'>[]\n      ];\n      type inverted3 = InvertPattern<pattern3, unknown>;\n      //    ^?\n      type test3 = Expect<Equal<inverted3, [string, boolean, ...number[]]>>;\n    });\n    it('[...a[], b]', () => {\n      type pattern1 = [\n        ...Matcher<any, GuardP<unknown, number>, 'array'>[],\n        'Hello'\n      ];\n      type inverted1 = InvertPattern<pattern1, unknown>;\n      //    ^?\n      type test1 = Expect<Equal<inverted1, [...number[], 'Hello']>>;\n\n      type pattern2 = [\n        ...Matcher<unknown, unknown, 'array'>[],\n        GuardP<unknown, unknown>\n      ];\n      type inverted2 = InvertPattern<pattern2, unknown>;\n      //    ^?\n      type test2 = Expect<Equal<inverted2, [...unknown[], unknown]>>;\n\n      type pattern3 = [\n        ...Matcher<any, GuardP<unknown, number>, 'array'>[],\n        GuardP<unknown, string>\n      ];\n      type inverted3 = InvertPattern<pattern3, unknown>;\n      //    ^?\n      type test3 = Expect<Equal<inverted3, [...number[], string]>>;\n    });\n    it('[...a[], b, c]', () => {\n      type pattern1 = [\n        ...Matcher<any, GuardP<unknown, number>, 'array'>[],\n        'Hello',\n        7\n      ];\n      type inverted1 = InvertPattern<pattern1, unknown>;\n      //    ^?\n      type test1 = Expect<Equal<inverted1, [...number[], 'Hello', 7]>>;\n\n      type pattern2 = [\n        ...Matcher<unknown, unknown, 'array'>[],\n        GuardP<unknown, unknown>,\n        GuardP<unknown, unknown>\n      ];\n      type inverted2 = InvertPattern<pattern2, unknown>;\n      //    ^?\n      type test2 = Expect<Equal<inverted2, [...unknown[], unknown, unknown]>>;\n\n      type pattern3 = [\n        ...Matcher<any, GuardP<unknown, number>, 'array'>[],\n        GuardP<unknown, string>,\n        GuardP<unknown, boolean>\n      ];\n      type inverted3 = InvertPattern<pattern3, unknown>;\n      //    ^?\n      type test3 = Expect<Equal<inverted3, [...number[], string, boolean]>>;\n    });\n    it('[a, ...b[], c]', () => {\n      type pattern1 = [\n        7,\n        ...Matcher<any, GuardP<unknown, number>, 'array'>[],\n        'Hello'\n      ];\n      type inverted1 = InvertPattern<pattern1, unknown>;\n      //    ^?\n      type test1 = Expect<Equal<inverted1, [7, ...number[], 'Hello']>>;\n\n      type pattern2 = [\n        GuardP<unknown, unknown>,\n        ...Matcher<unknown, unknown, 'array'>[],\n        GuardP<unknown, unknown>\n      ];\n      type inverted2 = InvertPattern<pattern2, unknown>;\n      //    ^?\n      type test2 = Expect<Equal<inverted2, [unknown, ...unknown[], unknown]>>;\n\n      type pattern3 = [\n        GuardP<unknown, string>,\n        ...Matcher<any, GuardP<unknown, number>, 'array'>[],\n        GuardP<unknown, boolean>\n      ];\n      type inverted3 = InvertPattern<pattern3, unknown>;\n      //    ^?\n      type test3 = Expect<Equal<inverted3, [string, ...number[], boolean]>>;\n    });\n\n    it('[a, b, ...c[], d, e]', () => {\n      type pattern1 = [\n        7,\n        8,\n        ...Matcher<any, GuardP<unknown, number>, 'array'>[],\n        'Hello',\n        'Bonjour'\n      ];\n      type inverted1 = InvertPattern<pattern1, undefined>;\n      //    ^?\n      type test1 = Expect<\n        Equal<inverted1, [7, 8, ...number[], 'Hello', 'Bonjour']>\n      >;\n\n      type pattern2 = [\n        GuardP<unknown, unknown>,\n        GuardP<unknown, unknown>,\n        ...Matcher<unknown, unknown, 'array'>[],\n        GuardP<unknown, unknown>,\n        GuardP<unknown, unknown>\n      ];\n      type inverted2 = InvertPattern<pattern2, undefined>;\n      //    ^?\n      type test2 = Expect<\n        Equal<inverted2, [unknown, unknown, ...unknown[], unknown, unknown]>\n      >;\n\n      type pattern3 = [\n        GuardP<unknown, string>,\n        GuardP<unknown, number>,\n        ...Matcher<any, GuardP<unknown, number>, 'array'>[],\n        GuardP<unknown, boolean>,\n        GuardP<unknown, symbol>\n      ];\n      type inverted3 = InvertPattern<pattern3, undefined>;\n      //    ^?\n      type test3 = Expect<\n        Equal<inverted3, [string, number, ...number[], boolean, symbol]>\n      >;\n    });\n  });\n});\n\ndescribe('InvertPatternForExclude', () => {\n  it('should correctly invert type guards', () => {\n    type cases = [\n      Expect<\n        Equal<\n          InvertPatternForExclude<\n            {\n              x: Matcher<1 | 2 | 3, 3>;\n            },\n            { x: 1 | 2 | 3 }\n          >,\n          Readonly<{ x: 3 }>\n        >\n      >,\n      Expect<\n        Equal<\n          InvertPatternForExclude<\n            {\n              x: Matcher<3, 3>;\n            },\n            { x: 1 } | { x: 2 } | { x: 3 }\n          >,\n          Readonly<{ x: 3 } | { x: 3 } | { x: 3 }>\n        >\n      >\n    ];\n  });\n\n  it('should work with objects', () => {\n    type res1 = InvertPatternForExclude<\n      { a: Matcher<unknown, string> },\n      { a: string; b: number } | [1, 2]\n    >;\n    type test1 = Expect<Equal<res1, Readonly<{ a: string }>>>;\n  });\n\n  describe('Tuples', () => {\n    it('should work with tuples', () => {\n      type res1 = InvertPatternForExclude<\n        [1, 2],\n        { a: string; b: number } | [1, 2]\n      >;\n      type test1 = Expect<Equal<res1, [1, 2]>>;\n    });\n\n    it('should return readonly tuples if the input tuple is readonly, not otherwise', () => {\n      type res1 = InvertPatternForExclude<\n        [[[1, 2]]],\n        { a: string } | readonly [[readonly [1, 2]]]\n      >;\n      type test1 = Expect<Equal<res1, readonly [[readonly [1, 2]]]>>;\n    });\n  });\n\n  describe('optional', () => {\n    type OptionalPattern<a> = Matcher<unknown, a, 'optional'>;\n\n    it('an optional pattern in an object should be considered an optional key', () => {\n      type input = { key?: 'a' | 'b' };\n      type pattern = { key: OptionalPattern<'a'> };\n      type inverted = InvertPatternForExclude<pattern, input>;\n\n      type cases = [\n        Expect<\n          Equal<\n            inverted,\n            Readonly<{\n              key?: 'a' | undefined;\n            }>\n          >\n        >\n      ];\n    });\n    it('the inverted value should be the intersection of all the inverted patterns', () => {\n      type x = InvertPatternForExclude<\n        { type2: 'c'; data: OptionalPattern<'f'> },\n        { type: 'a' | 'b'; type2: 'c' | 'd'; data?: 'f' | 'g' }\n      >;\n      type cases = [\n        Expect<Equal<x, Readonly<{ type2: 'c'; data?: 'f' | undefined }>>>\n      ];\n    });\n\n    it('an optional pattern in an object should be considered an optional key', () => {\n      type input = { key?: 'a' | 'b' };\n      type pattern = { key: OptionalPattern<'a'> };\n      type inverted = InvertPatternForExclude<pattern, input>;\n\n      type cases = [\n        Expect<\n          Equal<\n            inverted,\n            Readonly<{\n              key?: 'a' | undefined;\n            }>\n          >\n        >\n      ];\n    });\n  });\n\n  describe('variadic tuples', () => {\n    it('[a, ...b[]]', () => {\n      type pattern1 = ['Hello', ...Matcher<any, GuardP<unknown, 2>, 'array'>[]];\n      type input1 = { a: string; b: number } | [string, ...number[]];\n      type inverted1 = InvertPatternForExclude<pattern1, input1>;\n      type test1 = Expect<Equal<inverted1, ['Hello', ...2[]]>>;\n\n      type pattern2 = ['Hello', ...Matcher<any, GuardP<unknown, 2>, 'array'>[]];\n      type input2 = [string, ...number[]];\n      type inverted2 = InvertPatternForExclude<pattern2, input2>;\n      type test2 = Expect<Equal<inverted2, ['Hello', ...2[]]>>;\n\n      type pattern3 = [...Matcher<any, GuardP<unknown, 2>, 'array'>[]];\n      type input3 = [...number[]];\n      type inverted3 = InvertPatternForExclude<pattern3, input3>;\n      type test3 = Expect<Equal<inverted3, [...2[]]>>;\n\n      type pattern4 = readonly [\n        GuardP<unknown, unknown>,\n        ...ArrayP<unknown, unknown>[]\n      ];\n      type input4 = [string | number, ...(string | number)[]];\n      type inverted4 = InvertPatternForExclude<pattern4, input4>;\n      //    ^?\n      type test4 = Expect<Equal<inverted4, [unknown, ...(string | number)[]]>>;\n\n      type pattern5 = ArrayP<unknown, unknown>;\n      type input5 = (string | number)[];\n      type inverted5 = InvertPatternForExclude<pattern5, input5>;\n      type test5 = Expect<Equal<inverted5, (string | number)[]>>;\n    });\n\n    it('[a, b, ...c[]]', () => {\n      type pattern1 = [\n        'Hello',\n        10,\n        ...Matcher<any, GuardP<unknown, 2>, 'array'>[]\n      ];\n      type input1 = { a: string; b: number } | [string, number, ...number[]];\n      type inverted1 = InvertPatternForExclude<pattern1, input1>;\n      type test1 = Expect<Equal<inverted1, ['Hello', 10, ...2[]]>>;\n    });\n    it('[...a[], b]', () => {\n      type pattern1 = [\n        ...Matcher<any, GuardP<unknown, number>, 'array'>[],\n        'Hello'\n      ];\n      type input1 = { a: string; b: number } | [...number[], string];\n      type inverted1 = InvertPatternForExclude<pattern1, input1>;\n      type test1 = Expect<Equal<inverted1, [...number[], 'Hello']>>;\n    });\n    it('[...a[], b, c]', () => {\n      type pattern1 = [\n        ...Matcher<any, GuardP<unknown, number>, 'array'>[],\n        'Hello',\n        true\n      ];\n      type input1 = { a: string; b: number } | [...number[], string, boolean];\n      type inverted1 = InvertPatternForExclude<pattern1, input1>;\n      type test1 = Expect<Equal<inverted1, [...number[], 'Hello', true]>>;\n    });\n    it('[a, ...b[], c]', () => {\n      type pattern1 = [\n        'Hello',\n        ...Matcher<any, GuardP<unknown, number>, 'array'>[],\n        true\n      ];\n      type input1 = { a: string; b: number } | [string, ...number[], boolean];\n      type inverted1 = InvertPatternForExclude<pattern1, input1>;\n      type test1 = Expect<Equal<inverted1, ['Hello', ...number[], true]>>;\n    });\n  });\n});\n\ndescribe('issue #44', () => {\n  it('if the pattern contains unknown keys, inverted this pattern should keep them', () => {\n    type input = { sex: 'a' | 'b'; age: 'c' | 'd' };\n    type pattern = Readonly<{ sex: 'a'; unknownKey: 'c' }>;\n    type inverted = InvertPatternForExclude<pattern, input>;\n\n    type cases = [Expect<Equal<inverted, pattern>>];\n  });\n});\n\ndescribe('it should return never if the input pattern is Pattern<input>', () => {\n  it('InvertPattern', () => {\n    type input = { sex: 'a' | 'b'; age: 'c' | 'd' };\n    type pattern = Pattern<input>;\n    type inverted = InvertPattern<pattern, input>;\n    //    ^?\n    type test1 = Expect<Equal<inverted, never>>;\n  });\n\n  it('InvertPatternForExclude', () => {\n    type input = { sex: 'a' | 'b'; age: 'c' | 'd' };\n    type pattern = Pattern<input>;\n    type inverted = InvertPatternForExclude<pattern, input>;\n    //    ^?\n    type test1 = Expect<Equal<inverted, never>>;\n  });\n});\n"
  },
  {
    "path": "tests/is-matching.test.ts",
    "content": "import { isMatching, P } from '../src';\nimport { Equal, Expect } from '../src/types/helpers';\n\ndescribe('isMatching', () => {\n  it('should generate a type guard function from a pattern if given a single argument', () => {\n    const something: unknown = {\n      title: 'Hello',\n      author: { name: 'Gabriel', age: 27 },\n    };\n\n    const isBlogPost = isMatching({\n      title: P.string,\n      author: { name: P.string, age: P.number },\n    });\n\n    if (isBlogPost(something)) {\n      type t = Expect<\n        Equal<\n          typeof something,\n          { title: string; author: { name: string; age: number } }\n        >\n      >;\n      expect(true).toBe(true);\n    } else {\n      throw new Error(\n        'isMatching should have returned true but it returned false'\n      );\n    }\n  });\n\n  it('should act as a type guard function if given a two arguments', () => {\n    const something: unknown = {\n      title: 'Hello',\n      author: { name: 'Gabriel', age: 27 },\n    };\n\n    if (\n      isMatching(\n        {\n          title: P.string,\n          author: { name: P.string, age: P.number },\n        },\n        something\n      )\n    ) {\n      type t = Expect<\n        Equal<\n          typeof something,\n          { title: string; author: { name: string; age: number } }\n        >\n      >;\n      expect(true).toBe(true);\n    } else {\n      throw new Error(\n        'isMatching should have returned true but it returned false'\n      );\n    }\n  });\n\n  it('should work with object patterns', () => {\n    const value: unknown = { foo: true };\n    expect(isMatching({ foo: true }, value)).toEqual(true);\n    expect(isMatching({ foo: 'true' }, value)).toEqual(false);\n  });\n\n  it('should work with array patterns', () => {\n    const value: unknown = [1, 2, 3];\n    expect(isMatching(P.array(P.number), value)).toEqual(true);\n    expect(isMatching(P.array(P.string), value)).toEqual(false);\n  });\n\n  it('should work with variadic patterns', () => {\n    const value: unknown = [1, 2, 3];\n    expect(isMatching([1, ...P.array(P.number)], value)).toEqual(true);\n    expect(isMatching([2, ...P.array(P.number)], value)).toEqual(false);\n  });\n\n  it('should work with primitive patterns', () => {\n    const value: unknown = 1;\n    expect(isMatching(P.number, value)).toEqual(true);\n    expect(isMatching(P.boolean, value)).toEqual(false);\n  });\n\n  it('should work with literal patterns', () => {\n    const value: unknown = 1;\n    expect(isMatching(1, value)).toEqual(true);\n    expect(isMatching('oops', value)).toEqual(false);\n  });\n\n  it('should work with union and intersection patterns', () => {\n    const value: unknown = { foo: true };\n    expect(isMatching(P.union({ foo: true }, { bar: false }), value)).toEqual(\n      true\n    );\n\n    expect(isMatching(P.union({ foo: false }, { bar: false }), value)).toEqual(\n      false\n    );\n  });\n\n  type Pizza = { type: 'pizza'; topping: string };\n  type Sandwich = { type: 'sandwich'; condiments: string[] };\n  type Food = Pizza | Sandwich;\n\n  it('type inference should be precise without `as const`', () => {\n    const food = { type: 'pizza', topping: 'cheese' } as Food;\n\n    const isPizza = isMatching({ type: 'pizza' });\n\n    if (isPizza(food)) {\n      type t = Expect<Equal<typeof food, Pizza>>;\n    } else {\n      throw new Error('Expected food to match the pizza pattern!');\n    }\n\n    if (isMatching({ type: 'pizza' }, food)) {\n      type t = Expect<Equal<typeof food, Pizza>>;\n    } else {\n      throw new Error('Expected food to match the pizza pattern!');\n    }\n  });\n\n  it('should reject invalid pattern when two parameters are passed', () => {\n    const food = { type: 'pizza', topping: 'cheese' } as Food;\n\n    isMatching(\n      // @ts-expect-error\n      {\n        type: 'oops',\n      },\n      food\n    );\n  });\n\n  it('should allow patterns targetting one member of a union type', () => {\n    const food = { type: 'pizza', topping: 'cheese' } as Food;\n    expect(isMatching({ topping: 'cheese' }, food)).toBe(true);\n\n    if (isMatching({ topping: 'cheese' }, food)) {\n      type t = Expect<\n        Equal<typeof food, Pizza & { topping: 'cheese'; type: 'pizza' }>\n      >;\n    }\n  });\n\n  it('should allow targetting unknown properties', () => {\n    const food = { type: 'pizza', topping: 'cheese' } as Food;\n\n    expect(isMatching({ unknownProp: P.instanceOf(Error) }, food)).toBe(false);\n\n    if (isMatching({ unknownProp: P.instanceOf(Error) }, food)) {\n      type t = Expect<Equal<typeof food, Food & { unknownProp: Error }>>;\n    }\n  });\n\n  it('should correctly narrow undiscriminated unions of objects.', () => {\n    type Input = { someProperty: string[] } | { this: 'is a string' };\n    const input = { someProperty: ['hello'] } satisfies Input as Input;\n\n    if (isMatching({ someProperty: P.array() }, input)) {\n      expect(input.someProperty).toEqual(['hello']);\n      type t = Expect<Equal<typeof input.someProperty, string[]>>;\n    } else {\n      throw new Error('pattern should match');\n    }\n  });\n});\n"
  },
  {
    "path": "tests/large-exhaustive.test.ts",
    "content": "import { match, P } from '../src';\nimport { Compute, Equal, Expect, Not } from '../src/types/helpers';\n\ndescribe('large exhaustive', () => {\n  // prettier-ignore\n  type LargeObject<T> = Compute<{\n    a1: T; b1: T; c1: T; d1: T; e1: T; f1: T; g1: T; h1: T; i1: T; j1: T; k1: T; l1: T; m1: T; n1: T; o1: T; p1: T; q1: T; r1: T; s1: T; t1: T; u1: T; v1: T; w1: T; x1: T; y1: T; z1: T;\n    a2: T; b2: T; c2: T; d2: T; e2: T; f2: T; g2: T; h2: T; i2: T; j2: T; k2: T; l2: T; m2: T; n2: T; o2: T; p2: T; q2: T; r2: T; s2: T; t2: T; u2: T; v2: T; w2: T; x2: T; y2: T; z2: T;\n    a3: T; b3: T; c3: T; d3: T; e3: T; f3: T; g3: T; h3: T; i3: T; j3: T; k3: T; l3: T; m3: T; n3: T; o3: T; p3: T; q3: T; r3: T; s3: T; t3: T; u3: T; v3: T; w3: T; x3: T; y3: T; z3: T;\n}>;\n\n  it('large objects', () => {\n    expect(\n      match<LargeObject<number> | null>(null)\n        .with(\n          // prettier-ignore\n          {\n            a1: 0, b1: 0, c1: 0, d1: 0, e1: 0, f1: 0, g1: 0, h1: 0, i1: 0, j1: 0, k1: 0, l1: 0, m1: 0, n1: 0, o1: 0, p1: 0, q1: 0, r1: 0, s1: 0, t1: 0, u1: 0, v1: 0, w1: 0, x1: 0, y1: 0, z1: 0,\n            a2: 0, b2: 0, c2: 0, d2: 0, e2: 0, f2: 0, g2: 0, h2: 0, i2: 0, j2: 0, k2: 0, l2: 0, m2: 0, n2: 0, o2: 0, p2: 0, q2: 0, r2: 0, s2: 0, t2: 0, u2: 0, v2: 0, w2: 0, x2: 0, y2: 0, z2: 0,\n            a3: 0, b3: 0, c3: 0, d3: 0, e3: 0, f3: 0, g3: 0, h3: 0, i3: 0, j3: 0, k3: 0, l3: 0, m3: 0, n3: 0, o3: 0, p3: 0, q3: 0, r3: 0, s3: 0, t3: 0, u3: 0, v3: 0, w3: 0, x3: 0, y3: 0, z3: 0,\n          },\n          (x) => 'match'\n        )\n        .with(null, () => 'Null')\n        .with(\n          // prettier-ignore\n          {\n            a1: P.number, b1: P.number, c1: P.number, d1: P.number, e1: P.number, f1: P.number, g1: P.number, h1: P.number, i1: P.number, j1: P.number, k1: P.number, l1: P.number, m1: P.number, n1: P.number, o1: P.number, p1: P.number, q1: P.number, r1: P.number, s1: P.number, t1: P.number, u1: P.number, v1: P.number, w1: P.number, x1: P.number, y1: P.number, z1: P.number,\n            a2: P.number, b2: P.number, c2: P.number, d2: P.number, e2: P.number, f2: P.number, g2: P.number, h2: P.number, i2: P.number, j2: P.number, k2: P.number, l2: P.number, m2: P.number, n2: P.number, o2: P.number, p2: P.number, q2: P.number, r2: P.number, s2: P.number, t2: P.number, u2: P.number, v2: P.number, w2: P.number, x2: P.number, y2: P.number, z2: P.number,\n            a3: P.number, b3: P.number, c3: P.number, d3: P.number, e3: P.number, f3: P.number, g3: P.number, h3: P.number, i3: P.number, j3: P.number, k3: P.number, l3: P.number, m3: P.number, n3: P.number, o3: P.number, p3: P.number, q3: P.number, r3: P.number, s3: P.number, t3: P.number, u3: P.number, v3: P.number, w3: P.number, x3: P.number, y3: P.number, z3: P.number,\n          },\n          () => 'nope'\n        )\n        .exhaustive()\n    ).toBe('Null');\n  });\n\n  it('large tuple', () => {\n    expect(\n      match<\n        | [\n            LargeObject<number>,\n            LargeObject<number>,\n            LargeObject<number>,\n            LargeObject<number>,\n            LargeObject<number>\n          ]\n        | null\n      >(null)\n        .with(\n          // prettier-ignore\n          [\n            { \n              a1: 0, b1: 0, c1: 0, d1: 0, e1: 0, f1: 0, g1: 0, h1: 0, i1: 0, j1: 0, k1: 0, l1: 0, m1: 0, n1: 0, o1: 0, p1: 0, q1: 0, r1: 0, s1: 0, t1: 0, u1: 0, v1: 0, w1: 0, x1: 0, y1: 0, z1: 0,\n              a2: 0, b2: 0, c2: 0, d2: 0, e2: 0, f2: 0, g2: 0, h2: 0, i2: 0, j2: 0, k2: 0, l2: 0, m2: 0, n2: 0, o2: 0, p2: 0, q2: 0, r2: 0, s2: 0, t2: 0, u2: 0, v2: 0, w2: 0, x2: 0, y2: 0, z2: 0,\n              a3: 0, b3: 0, c3: 0, d3: 0, e3: 0, f3: 0, g3: 0, h3: 0, i3: 0, j3: 0, k3: 0, l3: 0, m3: 0, n3: 0, o3: 0, p3: 0, q3: 0, r3: 0, s3: 0, t3: 0, u3: 0, v3: 0, w3: 0, x3: 0, y3: 0, z3: 0,\n            },\n            { \n              a1: 0, b1: 0, c1: 0, d1: 0, e1: 0, f1: 0, g1: 0, h1: 0, i1: 0, j1: 0, k1: 0, l1: 0, m1: 0, n1: 0, o1: 0, p1: 0, q1: 0, r1: 0, s1: 0, t1: 0, u1: 0, v1: 0, w1: 0, x1: 0, y1: 0, z1: 0,\n              a2: 0, b2: 0, c2: 0, d2: 0, e2: 0, f2: 0, g2: 0, h2: 0, i2: 0, j2: 0, k2: 0, l2: 0, m2: 0, n2: 0, o2: 0, p2: 0, q2: 0, r2: 0, s2: 0, t2: 0, u2: 0, v2: 0, w2: 0, x2: 0, y2: 0, z2: 0,\n              a3: 0, b3: 0, c3: 0, d3: 0, e3: 0, f3: 0, g3: 0, h3: 0, i3: 0, j3: 0, k3: 0, l3: 0, m3: 0, n3: 0, o3: 0, p3: 0, q3: 0, r3: 0, s3: 0, t3: 0, u3: 0, v3: 0, w3: 0, x3: 0, y3: 0, z3: 0,\n            },\n            { \n              a1: 0, b1: 0, c1: 0, d1: 0, e1: 0, f1: 0, g1: 0, h1: 0, i1: 0, j1: 0, k1: 0, l1: 0, m1: 0, n1: 0, o1: 0, p1: 0, q1: 0, r1: 0, s1: 0, t1: 0, u1: 0, v1: 0, w1: 0, x1: 0, y1: 0, z1: 0,\n              a2: 0, b2: 0, c2: 0, d2: 0, e2: 0, f2: 0, g2: 0, h2: 0, i2: 0, j2: 0, k2: 0, l2: 0, m2: 0, n2: 0, o2: 0, p2: 0, q2: 0, r2: 0, s2: 0, t2: 0, u2: 0, v2: 0, w2: 0, x2: 0, y2: 0, z2: 0,\n              a3: 0, b3: 0, c3: 0, d3: 0, e3: 0, f3: 0, g3: 0, h3: 0, i3: 0, j3: 0, k3: 0, l3: 0, m3: 0, n3: 0, o3: 0, p3: 0, q3: 0, r3: 0, s3: 0, t3: 0, u3: 0, v3: 0, w3: 0, x3: 0, y3: 0, z3: 0,\n            },\n            {\n              a1: 0, b1: 0, c1: 0, d1: 0, e1: 0, f1: 0, g1: 0, h1: 0, i1: 0, j1: 0, k1: 0, l1: 0, m1: 0, n1: 0, o1: 0, p1: 0, q1: 0, r1: 0, s1: 0, t1: 0, u1: 0, v1: 0, w1: 0, x1: 0, y1: 0, z1: 0,\n              a2: 0, b2: 0, c2: 0, d2: 0, e2: 0, f2: 0, g2: 0, h2: 0, i2: 0, j2: 0, k2: 0, l2: 0, m2: 0, n2: 0, o2: 0, p2: 0, q2: 0, r2: 0, s2: 0, t2: 0, u2: 0, v2: 0, w2: 0, x2: 0, y2: 0, z2: 0,\n              a3: 0, b3: 0, c3: 0, d3: 0, e3: 0, f3: 0, g3: 0, h3: 0, i3: 0, j3: 0, k3: 0, l3: 0, m3: 0, n3: 0, o3: 0, p3: 0, q3: 0, r3: 0, s3: 0, t3: 0, u3: 0, v3: 0, w3: 0, x3: 0, y3: 0, z3: 0,\n            },\n            { \n              a1: 0, b1: 0, c1: 0, d1: 0, e1: 0, f1: 0, g1: 0, h1: 0, i1: 0, j1: 0, k1: 0, l1: 0, m1: 0, n1: 0, o1: 0, p1: 0, q1: 0, r1: 0, s1: 0, t1: 0, u1: 0, v1: 0, w1: 0, x1: 0, y1: 0, z1: 0,\n              a2: 0, b2: 0, c2: 0, d2: 0, e2: 0, f2: 0, g2: 0, h2: 0, i2: 0, j2: 0, k2: 0, l2: 0, m2: 0, n2: 0, o2: 0, p2: 0, q2: 0, r2: 0, s2: 0, t2: 0, u2: 0, v2: 0, w2: 0, x2: 0, y2: 0, z2: 0,\n              a3: 0, b3: 0, c3: 0, d3: 0, e3: 0, f3: 0, g3: 0, h3: 0, i3: 0, j3: 0, k3: 0, l3: 0, m3: 0, n3: 0, o3: 0, p3: 0, q3: 0, r3: 0, s3: 0, t3: 0, u3: 0, v3: 0, w3: 0, x3: 0, y3: 0, z3: 0,\n            }\n          ],\n          (x) => {\n            type test1 = Expect<Not<Equal<typeof x, never>>>;\n            type test2 = Expect<Not<Equal<typeof x, unknown>>>;\n            type test3 = Expect<Not<Equal<typeof x, any>>>;\n            return 'match';\n          }\n        )\n        .with(null, () => 'Null')\n        .with(\n          // prettier-ignore\n          [\n            { \n              a1: P.number, b1: P.number, c1: P.number, d1: P.number, e1: P.number, f1: P.number, g1: P.number, h1: P.number, i1: P.number, j1: P.number, k1: P.number, l1: P.number, m1: P.number, n1: P.number, o1: P.number, p1: P.number, q1: P.number, r1: P.number, s1: P.number, t1: P.number, u1: P.number, v1: P.number, w1: P.number, x1: P.number, y1: P.number, z1: P.number,\n              a2: P.number, b2: P.number, c2: P.number, d2: P.number, e2: P.number, f2: P.number, g2: P.number, h2: P.number, i2: P.number, j2: P.number, k2: P.number, l2: P.number, m2: P.number, n2: P.number, o2: P.number, p2: P.number, q2: P.number, r2: P.number, s2: P.number, t2: P.number, u2: P.number, v2: P.number, w2: P.number, x2: P.number, y2: P.number, z2: P.number,\n              a3: P.number, b3: P.number, c3: P.number, d3: P.number, e3: P.number, f3: P.number, g3: P.number, h3: P.number, i3: P.number, j3: P.number, k3: P.number, l3: P.number, m3: P.number, n3: P.number, o3: P.number, p3: P.number, q3: P.number, r3: P.number, s3: P.number, t3: P.number, u3: P.number, v3: P.number, w3: P.number, x3: P.number, y3: P.number, z3: P.number,\n            },\n            { \n              a1: P.number, b1: P.number, c1: P.number, d1: P.number, e1: P.number, f1: P.number, g1: P.number, h1: P.number, i1: P.number, j1: P.number, k1: P.number, l1: P.number, m1: P.number, n1: P.number, o1: P.number, p1: P.number, q1: P.number, r1: P.number, s1: P.number, t1: P.number, u1: P.number, v1: P.number, w1: P.number, x1: P.number, y1: P.number, z1: P.number,\n              a2: P.number, b2: P.number, c2: P.number, d2: P.number, e2: P.number, f2: P.number, g2: P.number, h2: P.number, i2: P.number, j2: P.number, k2: P.number, l2: P.number, m2: P.number, n2: P.number, o2: P.number, p2: P.number, q2: P.number, r2: P.number, s2: P.number, t2: P.number, u2: P.number, v2: P.number, w2: P.number, x2: P.number, y2: P.number, z2: P.number,\n              a3: P.number, b3: P.number, c3: P.number, d3: P.number, e3: P.number, f3: P.number, g3: P.number, h3: P.number, i3: P.number, j3: P.number, k3: P.number, l3: P.number, m3: P.number, n3: P.number, o3: P.number, p3: P.number, q3: P.number, r3: P.number, s3: P.number, t3: P.number, u3: P.number, v3: P.number, w3: P.number, x3: P.number, y3: P.number, z3: P.number,\n            },\n            { \n              a1: P.number, b1: P.number, c1: P.number, d1: P.number, e1: P.number, f1: P.number, g1: P.number, h1: P.number, i1: P.number, j1: P.number, k1: P.number, l1: P.number, m1: P.number, n1: P.number, o1: P.number, p1: P.number, q1: P.number, r1: P.number, s1: P.number, t1: P.number, u1: P.number, v1: P.number, w1: P.number, x1: P.number, y1: P.number, z1: P.number,\n              a2: P.number, b2: P.number, c2: P.number, d2: P.number, e2: P.number, f2: P.number, g2: P.number, h2: P.number, i2: P.number, j2: P.number, k2: P.number, l2: P.number, m2: P.number, n2: P.number, o2: P.number, p2: P.number, q2: P.number, r2: P.number, s2: P.number, t2: P.number, u2: P.number, v2: P.number, w2: P.number, x2: P.number, y2: P.number, z2: P.number,\n              a3: P.number, b3: P.number, c3: P.number, d3: P.number, e3: P.number, f3: P.number, g3: P.number, h3: P.number, i3: P.number, j3: P.number, k3: P.number, l3: P.number, m3: P.number, n3: P.number, o3: P.number, p3: P.number, q3: P.number, r3: P.number, s3: P.number, t3: P.number, u3: P.number, v3: P.number, w3: P.number, x3: P.number, y3: P.number, z3: P.number,\n            },\n            {\n              a1: P.number, b1: P.number, c1: P.number, d1: P.number, e1: P.number, f1: P.number, g1: P.number, h1: P.number, i1: P.number, j1: P.number, k1: P.number, l1: P.number, m1: P.number, n1: P.number, o1: P.number, p1: P.number, q1: P.number, r1: P.number, s1: P.number, t1: P.number, u1: P.number, v1: P.number, w1: P.number, x1: P.number, y1: P.number, z1: P.number,\n              a2: P.number, b2: P.number, c2: P.number, d2: P.number, e2: P.number, f2: P.number, g2: P.number, h2: P.number, i2: P.number, j2: P.number, k2: P.number, l2: P.number, m2: P.number, n2: P.number, o2: P.number, p2: P.number, q2: P.number, r2: P.number, s2: P.number, t2: P.number, u2: P.number, v2: P.number, w2: P.number, x2: P.number, y2: P.number, z2: P.number,\n              a3: P.number, b3: P.number, c3: P.number, d3: P.number, e3: P.number, f3: P.number, g3: P.number, h3: P.number, i3: P.number, j3: P.number, k3: P.number, l3: P.number, m3: P.number, n3: P.number, o3: P.number, p3: P.number, q3: P.number, r3: P.number, s3: P.number, t3: P.number, u3: P.number, v3: P.number, w3: P.number, x3: P.number, y3: P.number, z3: P.number,\n            },\n            { \n              a1: P.number, b1: P.number, c1: P.number, d1: P.number, e1: P.number, f1: P.number, g1: P.number, h1: P.number, i1: P.number, j1: P.number, k1: P.number, l1: P.number, m1: P.number, n1: P.number, o1: P.number, p1: P.number, q1: P.number, r1: P.number, s1: P.number, t1: P.number, u1: P.number, v1: P.number, w1: P.number, x1: P.number, y1: P.number, z1: P.number,\n              a2: P.number, b2: P.number, c2: P.number, d2: P.number, e2: P.number, f2: P.number, g2: P.number, h2: P.number, i2: P.number, j2: P.number, k2: P.number, l2: P.number, m2: P.number, n2: P.number, o2: P.number, p2: P.number, q2: P.number, r2: P.number, s2: P.number, t2: P.number, u2: P.number, v2: P.number, w2: P.number, x2: P.number, y2: P.number, z2: P.number,\n              a3: P.number, b3: P.number, c3: P.number, d3: P.number, e3: P.number, f3: P.number, g3: P.number, h3: P.number, i3: P.number, j3: P.number, k3: P.number, l3: P.number, m3: P.number, n3: P.number, o3: P.number, p3: P.number, q3: P.number, r3: P.number, s3: P.number, t3: P.number, u3: P.number, v3: P.number, w3: P.number, x3: P.number, y3: P.number, z3: P.number,\n            }\n          ],\n          () => 'nope'\n        )\n        .exhaustive()\n    ).toBe('Null');\n  });\n\n  // prettier-ignore\n  type DeepObject = {\n    1: { 2: { 3: { 4: {\n      a: number; b: number; c: number; d: number; e: number; f: number; g: number; h: number; i: number; j: number; k: number; l: number; m: number; n: number; o: number; p: number; q: number; r: number; s: number; t: number; u: number; v: number; w: number; x: number; y: number; z: number;\n    } } } }\n  };\n\n  it('deep objects', () => {\n    expect(\n      match<DeepObject | null>(null)\n        .with(\n          // prettier-ignore\n          { \n            1: { 2: { 3: { 4: {\n              a: 0, b: 0, c: 0, d: 0, e: 0, f: 0, g: 0, h: 0, i: 0, j: 0, k: 0, l: 0, m: 0, n: 0, o: 0, p: 0, q: 0, r: 0, s: 0, t: 0, u: 0, v: 0, w: 0, x: 0, y: 0, z: 0,\n            } } } }\n          },\n          (x) => 'match'\n        )\n        .with(null, () => 'Null')\n        .with(\n          // prettier-ignore\n          {\n            1: { 2: { 3: { 4: {\n              a: P.number, b: P.number, c: P.number, d: P.number, e: P.number, f: P.number, g: P.number, h: P.number, i: P.number, j: P.number, k: P.number, l: P.number, m: P.number, n: P.number, o: P.number, p: P.number, q: P.number, r: P.number, s: P.number, t: P.number, u: P.number, v: P.number, w: P.number, x: P.number, y: P.number, z: P.number, \n            } } } }\n          },\n          () => 'nope'\n        )\n        .exhaustive()\n    ).toBe('Null');\n  });\n\n  it('Input with a large distributed cardinality', () => {\n    type States = 'idle' | 'loading' | 'success' | 'error' | 'partial_result';\n\n    const eventStatus = 'success' as States;\n    const dataStatus = 'loading' as States;\n    const backgroundStatus = 'loading' as States;\n    const replaySelectorsStatus = 'idle' as States;\n\n    const input = {\n      eventStatus,\n      dataStatus,\n      backgroundStatus,\n      replaySelectorsStatus,\n    } as const;\n\n    type input = typeof input;\n\n    const res = match(input)\n      .returnType<\n        | { status: 'idle' }\n        | { status: 'loading' }\n        | { status: 'success' }\n        | { status: 'error'; error: unknown }\n      >()\n      .with(\n        { eventStatus: P.union('loading', 'partial_result') },\n        { dataStatus: P.union('loading', 'partial_result') },\n        { backgroundStatus: P.union('loading', 'partial_result') },\n        { replaySelectorsStatus: P.union('loading', 'partial_result') },\n        () => ({ status: 'loading' })\n      )\n      .with(\n        {\n          eventStatus: 'success',\n          dataStatus: 'success',\n          backgroundStatus: 'success',\n          replaySelectorsStatus: 'success',\n        },\n        () => ({ status: 'success' })\n      )\n      .with(\n        { eventStatus: 'idle' },\n        { dataStatus: 'idle' },\n        { backgroundStatus: 'idle' },\n        { replaySelectorsStatus: 'idle' },\n        () => ({ status: 'idle' as const })\n      )\n      .with({ replaySelectorsStatus: 'error' }, () => ({\n        status: 'error',\n        error: new Error('Oops 0'),\n      }))\n      .with({ eventStatus: 'error' }, () => ({\n        status: 'error',\n        error: new Error('Oops 1'),\n      }))\n      .with({ dataStatus: 'error' }, () => ({\n        status: 'error',\n        error: new Error('Oops 2'),\n      }))\n      .with({ backgroundStatus: 'error' }, () => ({\n        status: 'error',\n        error: new Error('Oops 3'),\n      }))\n      .exhaustive();\n  });\n});\n"
  },
  {
    "path": "tests/lists.test.ts",
    "content": "import { match, P } from '../src';\nimport { Expect, Equal } from '../src/types/helpers';\nimport { Option, Blog } from './types-catalog/utils';\n\ndescribe('List ([a])', () => {\n  it('should match list patterns', () => {\n    let httpResult = {\n      id: 20,\n      title: 'hellooo',\n    };\n    const res = match<any, Option<Blog[]>>([httpResult])\n      .with([], (x) => {\n        type t = Expect<Equal<typeof x, []>>;\n        return { kind: 'some', value: [{ id: 0, title: 'LOlol' }] };\n      })\n      .with(P.array({ id: P.number, title: P.string }), (blogs) => {\n        type t = Expect<Equal<typeof blogs, { id: number; title: string }[]>>;\n        return {\n          kind: 'some',\n          value: blogs,\n        };\n      })\n      .with(20, (x) => {\n        type t = Expect<Equal<typeof x, 20>>;\n        return { kind: 'none' };\n      })\n      .otherwise(() => ({ kind: 'none' }));\n\n    expect(res).toEqual({ kind: 'some', value: [httpResult] });\n  });\n\n  it('should work with generics', () => {\n    const reverse = <T>(xs: T[]): T[] => {\n      return match<T[], T[]>(xs)\n        .with([], () => [])\n        .with(P._, ([x, ...xs]) => [...reverse(xs), x])\n        .run();\n    };\n\n    expect(reverse([1, 2, 3])).toEqual([3, 2, 1]);\n  });\n\n  it('issue #148: P.array should support readonly arrays as its input', () => {\n    type Input = readonly {\n      readonly title: string;\n      readonly content: string;\n    }[];\n\n    const input: Input = [\n      { title: 'Hello world!', content: 'This is a very interesting content' },\n      { title: 'Bonjour!', content: 'This is a very interesting content too' },\n    ];\n\n    const output = match<Input, string>(input)\n      .with(\n        P.array({ title: P.string, content: P.string }),\n        (posts) => 'a list of posts!'\n      )\n      .otherwise(() => 'something else');\n  });\n\n  it('type narrowing should work on nested arrays', () => {\n    const fn = (input: { queries?: { q?: string[]; a: number }[] }) =>\n      match(input).with(\n        {\n          queries: P.array({ q: P.array(P.string) }),\n        },\n        (x) => {\n          type t = Expect<\n            Equal<typeof x, { queries: { a: number; q: string[] }[] }>\n          >;\n          return x.queries[0].q[0];\n        }\n      );\n  });\n});\n"
  },
  {
    "path": "tests/maps.test.ts",
    "content": "import { Expect, Equal } from '../src/types/helpers';\nimport { match, P } from '../src';\n\ndescribe('Map', () => {\n  it('should match Map patterns', () => {\n    const usersMap = new Map([\n      ['a', { name: 'alice' }],\n      ['b', { name: 'bob' }],\n    ]);\n\n    const userPattern = { name: P.string };\n\n    const res = match<Map<string, { name: string }>>(usersMap)\n      .with(P.map(P.union('b', 'a'), userPattern), (map) => ({\n        name: map.get('b')!.name + ' ' + map.get('a')!.name,\n      }))\n      .with(P.map('b', userPattern), (map) => map.get('b')!)\n      .with(P._, () => ({ name: 'unknown' }))\n      .run();\n\n    type t = Expect<Equal<typeof res, { name: string }>>;\n\n    expect(res).toEqual({ name: 'bob alice' });\n  });\n\n  it(\"should match any map if P.map isn't given any arguments\", () => {\n    const usersMap = new Map([\n      ['a', { name: 'alice' }],\n      ['b', { name: 'bob' }],\n    ]);\n\n    const res = match<Map<string, { name: string }>>(usersMap)\n      .with(P.map(), () => true)\n      .exhaustive();\n    type t = Expect<Equal<typeof res, boolean>>;\n    expect(res).toEqual(true);\n  });\n});\n"
  },
  {
    "path": "tests/matcher-protocol.test.ts",
    "content": "import { isMatching, match, P } from '../src';\nimport { Equal, Expect } from '../src/types/helpers';\n\ndescribe('matcher protocol', () => {\n  type SomeValue<T> = T extends Some<infer V> ? V : never;\n\n  interface SomeNarrowFn extends P.unstable_Fn {\n    output: Some<SomeValue<this['input']>>;\n  }\n\n  class Some<const T> {\n    constructor(public value: T) {}\n\n    static [P.matcher](): P.unstable_Matcher<SomeNarrowFn> {\n      return {\n        match: (input) => ({\n          matched: input instanceof Some,\n        }),\n      };\n    }\n\n    [P.matcher](): P.unstable_Matcher<\n      Some<T extends P.Pattern<unknown> ? P.infer<T> : T>\n    > {\n      return {\n        match: (input) => {\n          return {\n            matched:\n              input instanceof Some &&\n              isMatching<any, any>(this.value, input.value),\n          };\n        },\n      };\n    }\n  }\n\n  class None {\n    coucou: number;\n    constructor() {\n      this.coucou = 1;\n    }\n    static [P.matcher](): P.unstable_Matcher<None> {\n      return {\n        match: (input) => {\n          return { matched: input instanceof None };\n        },\n      };\n    }\n  }\n  type Option<T> = Some<T> | None;\n\n  it('should support taking a sub pattern', () => {\n    const res = match<{ option: Option<number | string> }>({\n      option: new Some(12),\n    })\n      .with({ option: new Some(7) }, (value) => {\n        type t = Expect<Equal<typeof value, { option: Some<7> }>>;\n        return value.option.value;\n      })\n      .with({ option: new Some(12) }, (value) => {\n        type t = Expect<Equal<typeof value, { option: Some<12> }>>;\n        return value.option.value;\n      })\n      .with({ option: None }, () => '')\n      .with({ option: Some }, () => '')\n      .exhaustive();\n\n    expect(res).toBe(12);\n\n    match<Option<number | string>>(new Some(12)).with(\n      new Some(P.number),\n      (some) => {\n        type t = Expect<Equal<typeof some, Some<number>>>;\n      }\n    );\n  });\n\n  it('should support nesting', () => {\n    const res = match<{ option: Option<number | string> }>({\n      option: new Some(12),\n    })\n      .with({ option: Some }, (x) => {\n        type t = Expect<Equal<typeof x, { option: Some<number | string> }>>;\n        return `Some ${x.option.value}`;\n      })\n      .with({ option: None }, (x) => {\n        type t = Expect<Equal<typeof x, { option: None }>>;\n        return 'None';\n      })\n      .exhaustive();\n\n    expect(res).toBe(`Some 12`);\n  });\n\n  it('it should work without nesting too', () => {\n    expect(\n      match<Option<number | string>>(new Some(12))\n        .with(new Some(10), (some) => {\n          type t = Expect<Equal<typeof some, Some<10>>>;\n          return `10`;\n        })\n        .with(new Some(12), (some) => `12`)\n        .with(new Some(P.any), (some) => `any`)\n        .with(None, () => 0)\n        .exhaustive()\n    ).toBe('12');\n\n    match<Option<number | string>>(new Some(12)).with(\n      new Some(P.number),\n      (some) => {\n        type t = Expect<Equal<typeof some, Some<number>>>;\n      }\n    );\n\n    match<Option<number | string>>(new Some(12))\n      .with(Some, (some) => {\n        type t = Expect<Equal<typeof some, Some<number | string>>>;\n      })\n      .with(None, (none) => {\n        type t = Expect<Equal<typeof none, None>>;\n      })\n      .exhaustive();\n  });\n});\n"
  },
  {
    "path": "tests/multiple-patterns.test.ts",
    "content": "import { match, P } from '../src';\nimport { Option } from './types-catalog/utils';\nimport { Expect, Equal } from '../src/types/helpers';\n\ndescribe('Multiple patterns', () => {\n  it('should match if one of the patterns matches', () => {\n    const testFn = (input: Option<number>) =>\n      match(input)\n        .with(\n          { kind: 'some', value: 2 as const },\n          { kind: 'some', value: 3 as const },\n          { kind: 'some', value: 4 as const },\n          (x) => {\n            type t = Expect<\n              Equal<\n                typeof x,\n                | { kind: 'some'; value: 2 }\n                | { kind: 'some'; value: 3 }\n                | { kind: 'some'; value: 4 }\n              >\n            >;\n            return true;\n          }\n        )\n        .with({ kind: 'none' }, { kind: 'some' }, (x) => {\n          type t = Expect<\n            Equal<typeof x, { kind: 'some'; value: number } | { kind: 'none' }>\n          >;\n          return false;\n        })\n        .run();\n\n    const cases = [\n      { input: { kind: 'some', value: 3 }, expected: true },\n      { input: { kind: 'some', value: 2 }, expected: true },\n      { input: { kind: 'some', value: 4 }, expected: true },\n      { input: { kind: 'some', value: 5 }, expected: false },\n      { input: { kind: 'some', value: -5 }, expected: false },\n    ] as const;\n\n    cases.forEach(({ input, expected }) => {\n      expect(testFn(input)).toBe(expected);\n    });\n  });\n\n  it('exhaustive patterns should match if one of the patterns matches', () => {\n    const testFn = (input: Option<number>) =>\n      match(input)\n        .with(\n          { kind: 'some', value: 2 as const },\n          { kind: 'some', value: 3 as const },\n          { kind: 'some', value: 4 as const },\n          (x) => {\n            type t = Expect<\n              Equal<\n                typeof x,\n                | { kind: 'some'; value: 2 }\n                | { kind: 'some'; value: 3 }\n                | { kind: 'some'; value: 4 }\n              >\n            >;\n            return true;\n          }\n        )\n        .with({ kind: 'none' }, { kind: 'some' }, (x) => {\n          type t = Expect<\n            Equal<typeof x, { kind: 'some'; value: number } | { kind: 'none' }>\n          >;\n          return false;\n        })\n        .exhaustive();\n\n    const cases = [\n      { input: { kind: 'some', value: 3 }, expected: true },\n      { input: { kind: 'some', value: 2 }, expected: true },\n      { input: { kind: 'some', value: 4 }, expected: true },\n      { input: { kind: 'some', value: 5 }, expected: false },\n      { input: { kind: 'some', value: -5 }, expected: false },\n    ] as const;\n\n    cases.forEach(({ input, expected }) => {\n      expect(testFn(input)).toBe(expected);\n    });\n  });\n\n  it(\"no patterns shouldn't typecheck\", () => {\n    const input = { kind: 'none' } as Option<number>;\n    match(input)\n      // @ts-expect-error: Argument of type '() => false' is not assignable to parameter of type 'ExhaustivePattern<Option<number>>'\n      .with(() => false);\n  });\n\n  it('should work with literal types', () => {\n    type Country = 'France' | 'Germany' | 'Spain' | 'USA';\n\n    match<Country>('France')\n      .with('France', 'Germany', 'Spain', () => 'Europe')\n      .with('USA', () => 'America')\n      .exhaustive();\n\n    match<Country>('Germany')\n      .with('Germany', 'Spain', () => 'Europe')\n      .with('USA', () => 'America')\n      // @ts-expect-error: 'France' is missing\n      .exhaustive();\n  });\n\n  it('should work with nullables', () => {\n    match<null | undefined>(null)\n      .with(null, undefined, (x) => 'Nullable')\n      .exhaustive();\n  });\n\n  it('should work with objects', () => {\n    match<{ a: string; b: number } | [1, 2]>({ a: '', b: 2 })\n      .with({ a: P.string }, (x) => 'obj')\n      .with([1, 2], (x) => 'tuple')\n      .exhaustive();\n\n    match<{ a: string; b: number } | [1, 2]>({ a: '', b: 2 })\n      .with({ a: P.string }, [1, 2], (x) => 'obj')\n      .exhaustive();\n  });\n\n  it('should work with all types of input', () => {\n    type Input =\n      | null\n      | undefined\n      | number\n      | string\n      | boolean\n      | { a: string; b: number }\n      | [boolean, number]\n      | Map<string, { x: number }>\n      | Set<number>;\n\n    const nonExhaustive = (input: Input) =>\n      match<Input>(input)\n        .with(null, undefined, (x) => {\n          type t = Expect<Equal<typeof x, null | undefined>>;\n          return 'Nullable';\n        })\n        .with(P.boolean, P.number, P.string, (x) => {\n          type t = Expect<Equal<typeof x, boolean | number | string>>;\n          return 'primitive';\n        })\n        .with(\n          { a: P.string },\n          [true, 2],\n          P.map('key', P._),\n          P.set(P.number),\n          (x) => {\n            type t = Expect<\n              Equal<\n                typeof x,\n                | { a: string; b: number }\n                | [true, 2]\n                | Map<'key', { x: number }>\n                | Set<number>\n              >\n            >;\n\n            return 'Object';\n          }\n        )\n        .with([false, 2], (x) => {\n          type t = Expect<Equal<typeof x, [false, 2]>>;\n          return '[false, 2]';\n        })\n        .with([false, P.number], (x) => {\n          type t = Expect<Equal<typeof x, [false, number]>>;\n          return '[false, number]';\n        })\n        .with([true, P.number], (x) => {\n          type t = Expect<Equal<typeof x, [true, number]>>;\n          return '[true, number]';\n        })\n        .run();\n\n    const exhaustive = (input: Input) =>\n      match<Input>(input)\n        .with(null, undefined, (x) => 'Nullable')\n        .with(P.boolean, P.number, P.string, (x) => 'primitive')\n        .with(\n          { a: P.string },\n          [true, 2],\n          P.map(P.string, P._),\n          P.set(P.number),\n          (x) => 'Object'\n        )\n        .with([false, 2], (x) => '[false, 2]')\n        .with([false, P.number], (x) => '[false, number]')\n        .with([true, P.number], (x) => '[true, number]')\n        .exhaustive();\n\n    const cases: { input: Input; expected: string }[] = [\n      { input: null, expected: 'Nullable' },\n      { input: undefined, expected: 'Nullable' },\n      { input: true, expected: 'primitive' },\n      { input: 2, expected: 'primitive' },\n      { input: 'string', expected: 'primitive' },\n      { input: { a: 'hello', b: 2 }, expected: 'Object' },\n      { input: [true, 2], expected: 'Object' },\n      { input: new Map([['key', { x: 2 }]]), expected: 'Object' },\n      { input: new Set([2]), expected: 'Object' },\n      { input: [false, 2], expected: '[false, 2]' },\n      { input: [false, 3], expected: '[false, number]' },\n    ];\n\n    cases.forEach(({ input, expected }) => {\n      expect(nonExhaustive(input)).toEqual(expected);\n      expect(exhaustive(input)).toEqual(expected);\n    });\n  });\n\n  it(\"when 2 returned values don't match, the error should be at the second returned value\", () => {\n    const f = (input: { t: 'a'; x: any } | { t: 'b' }) =>\n      match<typeof input, string>(input)\n        .with({ t: 'a', x: 'hello' }, { t: 'a' }, (x) => 'ok')\n        // @ts-expect-error\n        .with({ t: 'b' }, (x) => 2)\n        .run();\n  });\n\n  it('issue #74: inference must work on every pattern in the list', () => {\n    match<{ a: number[] }>({ a: [1, 2, 3, 4] })\n      .with(\n        {\n          a: P.when((arr) => {\n            type t = Expect<Equal<typeof arr, number[]>>;\n            return arr.length === 4;\n          }),\n        },\n        {\n          a: P.when((arr) => {\n            type t = Expect<Equal<typeof arr, number[]>>;\n            return arr.length === 4;\n          }),\n        },\n        {\n          a: P.when((arr) => {\n            type t = Expect<Equal<typeof arr, number[]>>;\n            return arr.length === 4;\n          }),\n        },\n        ({ a }) => {}\n      )\n      .with({ a: P.array(P.number) }, () => {})\n      .exhaustive();\n  });\n});\n"
  },
  {
    "path": "tests/narrow.test.ts",
    "content": "import { P, match } from '../src';\nimport { Equal, Expect } from '../src/types/helpers';\n\ndescribe('P.narrow', () => {\n  it('should correctly narrow the input type', () => {\n    type Input = ['a' | 'b' | 'c', 'a' | 'b' | 'c'];\n    const Pattern = ['a', P.union('a', 'b')] as const;\n\n    type Narrowed = P.narrow<Input, typeof Pattern>;\n    //     ^?\n    type test = Expect<Equal<Narrowed, ['a', 'a' | 'b']>>;\n  });\n});\n\ndescribe('.narrow() method', () => {\n  it('should excluded values from deeply nested union types.', () => {\n    const fn = (input: { prop?: string }) =>\n      match(input)\n        .with({ prop: P.nullish.optional() }, () => false)\n        .narrow()\n        .otherwise(({ prop }) => {\n          type test = Expect<Equal<typeof prop, string>>;\n          return true;\n        });\n  });\n\n  const fn2 = (input: { prop?: 1 | 2 | 3 }) =>\n    match(input)\n      .with({ prop: P.nullish.optional() }, () => false)\n      .with({ prop: 2 }, () => false)\n      .narrow()\n      .otherwise(({ prop }) => {\n        type test = Expect<Equal<typeof prop, 1 | 3>>;\n        return true;\n      });\n});\n"
  },
  {
    "path": "tests/nesting.test.ts",
    "content": "import { Expect, Equal } from '../src/types/helpers';\nimport { match, P } from '../src';\n\ndescribe('Nesting', () => {\n  describe('deeply nested objects', () => {\n    it('should work with 4 levels of object nesting', () => {\n      type Post = {\n        type: 'post';\n        id: number;\n        content: { body: string; video: Video };\n      };\n      type Video = { type: 'video'; id: number; content: { src: string } };\n\n      const res = match<Post>({\n        type: 'post',\n        id: 2,\n        content: {\n          body: 'yo',\n          video: { type: 'video', content: { src: '' }, id: 2 },\n        },\n      })\n        .with(\n          { type: 'post', content: { video: { id: 2, content: { src: '' } } } },\n          (x) => {\n            type t = Expect<\n              Equal<\n                typeof x,\n                {\n                  id: number;\n                  type: 'post';\n                  content: {\n                    body: string;\n                    video: {\n                      type: 'video';\n                      id: 2;\n                      content: {\n                        src: '';\n                      };\n                    };\n                  };\n                }\n              >\n            >;\n            return 1;\n          }\n        )\n        .with(P.any, () => 1)\n        .exhaustive();\n\n      type t = Expect<Equal<typeof res, number>>;\n\n      expect(res).toEqual(1);\n    });\n  });\n  describe('objects', () => {\n    it('it should work on 2 level', () => {\n      expect(\n        match({ one: { two: '2', foo: 2, bar: true } })\n          .with({ one: { foo: P.any, bar: P.any } }, (x) => x.one.bar)\n          .exhaustive()\n      ).toEqual(true);\n    });\n\n    it('it should work on 3 level', () => {\n      expect(\n        match({ one: { two: { three: '2', foo: 2, bar: true } } })\n          .with(\n            { one: { two: { foo: P.any, bar: P.any } } },\n            (x) => x.one.two.bar\n          )\n          .exhaustive()\n      ).toEqual(true);\n    });\n\n    it('it should work on 4 level', () => {\n      expect(\n        match({ one: { two: { three: { four: '2', foo: 2, bar: true } } } })\n          .with(\n            { one: { two: { three: { foo: P.any, bar: P.any } } } },\n            (x) => x.one.two.three.bar\n          )\n          .exhaustive()\n      ).toEqual(true);\n    });\n\n    it('it should work on 5 level', () => {\n      expect(\n        match({\n          one: { two: { three: { four: { five: '2', foo: 2, bar: true } } } },\n        })\n          .with(\n            { one: { two: { three: { four: { foo: P.any, bar: P.any } } } } },\n            (x) => x.one.two.three.four.bar\n          )\n          .exhaustive()\n      ).toEqual(true);\n    });\n\n    it('it should work on 17 level', () => {\n      expect(\n        match({\n          // prettier-ignore\n          a: { a: { a: { a: { a: { a: { a: { a: { a: {a: { a: { a: { a: { a: { a: { a: { a: { a: { a: {\n            foo: 2,\n            bar: true,\n          }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, },\n        })\n          .with(\n            {\n              // prettier-ignore\n              a: { a: { a: { a: { a: { a: { a: { a: { a: {a: { a: { a: { a: { a: { a: { a: { a: { a: { a: {\n                foo: P.any,\n                bar: P.select('bar'),\n              }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, }, },\n            },\n            (_, x) => x.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.bar\n          )\n          .exhaustive()\n      ).toEqual(true);\n    });\n  });\n\n  describe('array', () => {\n    it('it should work on 2 levels', () => {\n      expect(\n        match([{ two: '2', foo: 2, bar: true }])\n          .with([{ foo: P.any, bar: P.select('bar') }], ({ bar }) => bar)\n          .exhaustive()\n      ).toEqual(true);\n    });\n\n    it('it should work on 3 levels', () => {\n      expect(\n        match([[{ two: '2', foo: 2, bar: true }]])\n          .with([[{ foo: P.any, bar: P.select('bar') }]], ({ bar }) => bar)\n          .exhaustive()\n      ).toEqual(true);\n    });\n\n    it('it should work on 4 levels', () => {\n      expect(\n        match([[[{ two: '2', foo: 2, bar: true }]]])\n          .with([[[{ foo: P.any, bar: P.select('bar') }]]], ({ bar }) => bar)\n          .exhaustive()\n      ).toEqual(true);\n    });\n\n    it('it should work on 5 levels', () => {\n      expect(\n        match([[[[{ two: '2', foo: 2, bar: true }]]]])\n          .with([[[[{ foo: P.any, bar: P.any }]]]], ([[[[{ bar }]]]]) => bar)\n          .exhaustive()\n      ).toEqual(true);\n    });\n\n    it('it should work on 17 levels', () => {\n      expect(\n        match([\n          [[[[[[[[[[[[[[[[[{ two: '2', foo: 2, bar: true }]]]]]]]]]]]]]]]]],\n        ] as const)\n          .with(\n            // prettier-ignore\n            [[[[[[[[[[[[[[[[[[{ foo: P.any, bar: P.select('bar') }]]]]]]]]]]]]]]]]]],\n            ({ bar }) => bar\n          )\n          .exhaustive()\n      ).toEqual(true);\n    });\n  });\n});\n"
  },
  {
    "path": "tests/not.test.ts",
    "content": "import { Expect, Equal } from '../src/types/helpers';\nimport { match, P } from '../src';\nimport { Option } from './types-catalog/utils';\n\ndescribe('not', () => {\n  it('should work at the top level', () => {\n    const get = (x: unknown): string =>\n      match(x)\n        .with(P.not(P.number), (x) => {\n          type t = Expect<Equal<typeof x, unknown>>;\n          return 'not a number';\n        })\n        .with(P.not(P.string), (x) => {\n          type t = Expect<Equal<typeof x, unknown>>;\n          return 'not a string';\n        })\n        .run();\n\n    expect(get(20)).toEqual('not a string');\n    expect(get('hello')).toEqual('not a number');\n  });\n\n  it('should work in a nested structure', () => {\n    type DS = { x: string | number; y: string | number };\n    const get = (x: DS) =>\n      match(x)\n        .with({ y: P.number, x: P.not(P.string) }, (x) => {\n          type t = Expect<Equal<typeof x, { x: number; y: number }>>;\n          return 'yes';\n        })\n        .with(P.any, () => 'no')\n        .run();\n\n    expect(get({ x: 2, y: 2 })).toEqual('yes');\n    expect(get({ y: 2, x: 'hello' })).toEqual('no');\n  });\n\n  it('should discriminate union types correctly', () => {\n    const one = 'one';\n    const two = 'two';\n\n    const get = (x: 'one' | 'two') =>\n      match(x)\n        .with(P.not(one), (x) => {\n          type t = Expect<Equal<typeof x, 'two'>>;\n          return 'not 1';\n        })\n        .with('one', (x) => {\n          type t = Expect<Equal<typeof x, 'one'>>;\n          return 'not 2';\n        })\n        .exhaustive();\n\n    expect(get('two')).toEqual('not 1');\n    expect(get('one')).toEqual('not 2');\n  });\n\n  it('should discriminate union types contained in objects correctly', () => {\n    const one = 'one';\n    const two = 'two';\n\n    const get = (x: 'one' | 'two') =>\n      match({ key: x })\n        .with({ key: P.not(one) }, (x) => {\n          type t = Expect<Equal<typeof x, { key: 'two' }>>;\n          return 'not 1';\n        })\n        .with({ key: P.not(two) }, (x) => {\n          type t = Expect<Equal<typeof x, { key: 'one' }>>;\n          return 'not 2';\n        })\n        .run();\n\n    expect(get('two')).toEqual('not 1');\n    expect(get('one')).toEqual('not 2');\n  });\n\n  it('should discriminate union types correctly', () => {\n    type Input =\n      | {\n          type: 'success';\n        }\n      | { type: 'error' };\n\n    const get = (x: Input) =>\n      match(x)\n        .with({ type: P.not('success') }, (x) => {\n          type t = Expect<Equal<typeof x, { type: 'error' }>>;\n          return 'error';\n        })\n        .with({ type: 'success' }, (x) => {\n          type t = Expect<Equal<typeof x, { type: 'success' }>>;\n          return 'success';\n        })\n        .exhaustive();\n\n    expect(get({ type: 'error' })).toEqual('error');\n    expect(get({ type: 'success' })).toEqual('success');\n  });\n\n  it('should correctly invert the type of a Matcher', () => {\n    const nullable = P.when(\n      (x: unknown): x is null | undefined => x === null || x === undefined\n    );\n\n    expect(\n      match<{ str: string } | null>({ str: 'hello' })\n        .with(P.not(nullable), ({ str }) => str)\n        .with(nullable, () => '')\n        .exhaustive()\n    ).toBe('hello');\n\n    const untypedNullable = P.when(\n      (x): boolean => x === null || x === undefined\n    );\n\n    expect(\n      match<{ str: string }>({ str: 'hello' })\n        .with(P.not(untypedNullable), ({ str }) => str)\n        // @ts-expect-error\n        .exhaustive()\n    ).toBe('hello');\n  });\n\n  it('should correctly exclude unit types with the unit wildcard', () => {\n    expect(\n      match<{ str: string | null | undefined }>({ str: 'hello' })\n        .with({ str: P.not(P.nullish) }, ({ str }) => {\n          type t = Expect<Equal<typeof str, string>>;\n\n          return str;\n        })\n        .with({ str: P.nullish }, ({ str }) => {\n          type t = Expect<Equal<typeof str, null | undefined>>;\n\n          return null;\n        })\n        .exhaustive()\n    ).toBe('hello');\n  });\n\n  it(\"shouldn't change a the type if its any or unknown\", () => {\n    expect(\n      match<{ str: any }>({ str: 'hello' })\n        .with({ str: P.not(P.nullish) }, (x) => {\n          type t = Expect<Equal<typeof x, { str: any }>>;\n          return 'hello';\n        })\n        .otherwise(() => 'no')\n    ).toBe('hello');\n  });\n\n  it('should successfully exclude cases ', () => {\n    const f = (\n      optionalNumber: Option<{\n        coords: { x: 'left' | 'right'; y: 'top' | 'bottom' };\n      }>\n    ) =>\n      match(optionalNumber)\n        .with(\n          {\n            type: 'some',\n            value: {\n              coords: P.not({ x: 'left' }),\n            },\n          },\n          (x) => {\n            type t = Expect<\n              Equal<\n                (typeof x)['value']['coords'],\n                {\n                  y: 'top' | 'bottom';\n                  x: 'right';\n                }\n              >\n            >;\n\n            return 'ok';\n          }\n        )\n        .otherwise(() => 'not ok');\n  });\n\n  it('should consider the expression exhaustive if the sub pattern matches something that will never match', () => {\n    expect(\n      match<{ str: string }>({ str: 'hello' })\n        .with(P.not(P.number), ({ str }) => str)\n        .exhaustive()\n    ).toBe('hello');\n\n    expect(() =>\n      match<number>(1)\n        .with(P.not(P.number), (n) => n)\n        // @ts-expect-error\n        .exhaustive()\n    ).toThrow();\n  });\n\n  it('Doc example', () => {\n    type Input =\n      | string\n      | number\n      | boolean\n      | { key: string }\n      | string[]\n      | [number, number];\n\n    const notMatch = (value: Input) =>\n      match(value)\n        .with(P.not(P.string), (value) => `value is NOT a string: ${value}`)\n        .with(P.not(P.number), (value) => `value is NOT a number: ${value}`)\n        .with(P.not(P.boolean), (value) => `value is NOT a boolean: ${value}`)\n        .exhaustive();\n\n    const inputs: { input: Input; expected: string }[] = [\n      { input: 'Hello', expected: 'value is NOT a number: Hello' },\n      { input: 20, expected: 'value is NOT a string: 20' },\n      { input: true, expected: 'value is NOT a string: true' },\n      {\n        input: { key: 'value' },\n        expected: 'value is NOT a string: [object Object]',\n      },\n      {\n        input: ['bonjour', 'hola'],\n        expected: 'value is NOT a string: bonjour,hola',\n      },\n      { input: [1, 2], expected: 'value is NOT a string: 1,2' },\n    ];\n\n    inputs.forEach(({ input, expected }) =>\n      expect(notMatch(input)).toEqual(expected)\n    );\n  });\n\n  it(\"issue #138 — P.not on literals shouln't exclude the whole primitive type.\", () => {\n    type Input =\n      | { type: 'user'; name: string }\n      | { type: 'image'; src: string }\n      | { type: 'video'; seconds: number };\n\n    let input = { type: 'user', name: 'Gabriel' } as unknown as Input;\n\n    match(input)\n      .with(\n        { type: 'video', seconds: P.not(10) },\n        () => 'not video of 10 seconds.'\n      )\n      // This should work\n      .with({ type: 'video', seconds: 10 }, () => 'video of 10 seconds.')\n      .otherwise(() => 'something else');\n  });\n\n  it(\"shouldn't consider unexhaustive patterns exhaustive\", () => {\n    const f = (input: { type: 'video'; seconds: number }) =>\n      match(input)\n        .with(\n          // not 10, but still can be any number.\n          { type: 'video', seconds: P.not(10) },\n          () => 'not video of 10 seconds.'\n        )\n        // @ts-expect-error\n        .exhaustive();\n  });\n\n  it('exhaustive should work when P.not is followed by the anti-pattern', () => {\n    match<number>(1)\n      .with(P.not(P.number), () => 'not 2')\n      .with(P.number, () => '2')\n      .exhaustive();\n\n    match<1 | 2>(1)\n      .with(P.not(2), () => '1')\n      .with(2, () => '2')\n      .exhaustive();\n\n    match<'a' | 'b' | 'c'>('a')\n      .with(P.not('a'), () => '1')\n      .with('a', () => '2')\n      .exhaustive();\n\n    match<number>(1)\n      .with(P.not(2), () => 'not 2')\n      .with(2, () => '2')\n      // FIXME: Technically, this pattern is exhaustive but I don't see a way to make sure it is\n      // without negated types (https://github.com/microsoft/TypeScript/pull/29317).\n      // @ts-expect-error\n      .exhaustive();\n  });\n});\n"
  },
  {
    "path": "tests/numbers.test.ts",
    "content": "import { Expect, Equal } from '../src/types/helpers';\nimport { match, P } from '../src';\n\ndescribe('Numbers', () => {\n  it('Should match exact numbers', () => {\n    const res = match<number>(1)\n      .with(1, (v) => {\n        type t = Expect<Equal<typeof v, 1>>;\n        return v * 2;\n      })\n      .with(2, (v) => {\n        type t = Expect<Equal<typeof v, 2>>;\n        return v * v;\n      })\n      .otherwise(() => -1);\n\n    type t = Expect<Equal<typeof res, number>>;\n\n    expect(res).toEqual(2);\n  });\n\n  it('P.number should match NaN', () => {\n    const val: number | null = NaN;\n    const res = match(val)\n      .with(P.nullish, () => 'bad')\n      .with(1, () => 'bad')\n      .with(P.number, () => 'good')\n      .exhaustive();\n\n    expect(res).toEqual('good');\n  });\n\n  it('NaN should match NaN specially', () => {\n    const val: number | null = NaN;\n    const res = match(val)\n      .with(P.nullish, () => 'bad')\n      .with(1, () => 'bad')\n      .with(NaN, () => 'good')\n      .with(P.number, () => 'bad')\n      .exhaustive();\n\n    expect(res).toEqual('good');\n  });\n\n  it(\"when matching only NaN, the expression shouldn't be exhaustive\", () => {\n    const f = (val: number) =>\n      match(val)\n        .with(NaN, () => 'NaN')\n        // @ts-expect-error\n        .exhaustive();\n\n    const f2 = (val: number) =>\n      match(val)\n        .with(NaN, () => 'NaN')\n        .with(P.number, () => 'number')\n        .exhaustive();\n  });\n\n  describe('chainable', () => {\n    it(`P.number.between(1, 10)`, () => {\n      const f = (input: string | number) =>\n        match(input)\n          .with(P.number.between(0, 10), (value) => {\n            type t = Expect<Equal<typeof value, number>>;\n            return 'between 0 and 10';\n          })\n          .otherwise((value) => {\n            type t = Expect<Equal<typeof value, string | number>>;\n            return 'something else';\n          });\n\n      expect(f(5)).toBe('between 0 and 10');\n      expect(f(0)).toBe('between 0 and 10');\n      expect(f(10)).toBe('between 0 and 10');\n      expect(f('gabriel')).toBe('something else');\n    });\n\n    it(`P.number.lt(..)`, () => {\n      const f = (input: string | number | bigint) =>\n        match(input)\n          .with(P.number.lt(10), (value) => {\n            type t = Expect<Equal<typeof value, number>>;\n            return 'yes';\n          })\n          .otherwise((value) => {\n            type t = Expect<Equal<typeof value, string | number | bigint>>;\n            return 'no';\n          });\n\n      expect(f(5)).toBe('yes');\n      expect(f(12)).toBe('no');\n      expect(f(10n)).toBe('no');\n    });\n    it(`P.number.gt(..)`, () => {\n      const f = (input: string | number | bigint) =>\n        match(input)\n          .with(P.number.gt(10), (value) => {\n            type t = Expect<Equal<typeof value, number>>;\n            return 'yes';\n          })\n          .otherwise((value) => {\n            type t = Expect<Equal<typeof value, string | number | bigint>>;\n            return 'no';\n          });\n\n      expect(f(5)).toBe('no');\n      expect(f(10)).toBe('no');\n      expect(f(12)).toBe('yes');\n    });\n    it(`P.number.gte(..)`, () => {\n      const f = (input: string | number | bigint) =>\n        match(input)\n          .with(P.number.gte(10), (value) => {\n            type t = Expect<Equal<typeof value, number>>;\n            return 'yes';\n          })\n          .otherwise((value) => {\n            type t = Expect<Equal<typeof value, string | number | bigint>>;\n            return 'no';\n          });\n\n      expect(f(5)).toBe('no');\n      expect(f(10)).toBe('yes');\n      expect(f(12)).toBe('yes');\n    });\n    it(`P.number.lte(..)`, () => {\n      const f = (input: string | number | bigint) =>\n        match(input)\n          .with(P.number.lte(10), (value) => {\n            type t = Expect<Equal<typeof value, number>>;\n            return 'yes';\n          })\n          .otherwise((value) => {\n            type t = Expect<Equal<typeof value, string | number | bigint>>;\n            return 'no';\n          });\n\n      expect(f(5)).toBe('yes');\n      expect(f(10)).toBe('yes');\n      expect(f(12)).toBe('no');\n    });\n    it(`P.number.int(..)`, () => {\n      const f = (input: string | number | bigint) =>\n        match(input)\n          .with(P.number.int(), (value) => {\n            type t = Expect<Equal<typeof value, number>>;\n            return 'yes';\n          })\n          .otherwise((value) => {\n            type t = Expect<Equal<typeof value, string | number | bigint>>;\n            return 'no';\n          });\n\n      expect(f(5)).toBe('yes');\n      expect(f(10.123)).toBe('no');\n      expect(f(-Infinity)).toBe('no');\n    });\n    it(`P.number.finite()`, () => {\n      const f = (input: string | number | bigint) =>\n        match(input)\n          .with(P.number.finite(), (value) => {\n            type t = Expect<Equal<typeof value, number>>;\n            return 'yes';\n          })\n          .otherwise((value) => {\n            type t = Expect<Equal<typeof value, string | number | bigint>>;\n            return 'no';\n          });\n\n      expect(f(5)).toBe('yes');\n      expect(f(10.123)).toBe('yes');\n      expect(f(-Infinity)).toBe('no');\n    });\n    it(`P.number.positive()`, () => {\n      const f = (input: string | number | bigint) =>\n        match(input)\n          .with(P.number.positive(), (value) => {\n            type t = Expect<Equal<typeof value, number>>;\n            return 'yes';\n          })\n          .otherwise((value) => {\n            type t = Expect<Equal<typeof value, string | number | bigint>>;\n            return 'no';\n          });\n\n      expect(f(5)).toBe('yes');\n      expect(f(10.123)).toBe('yes');\n      expect(f(-10.123)).toBe('no');\n      expect(f(-Infinity)).toBe('no');\n    });\n    it(`P.number.negative()`, () => {\n      const f = (input: string | number | bigint) =>\n        match(input)\n          .with(P.number.negative(), (value) => {\n            type t = Expect<Equal<typeof value, number>>;\n            return 'yes';\n          })\n          .otherwise((value) => {\n            type t = Expect<Equal<typeof value, string | number | bigint>>;\n            return 'no';\n          });\n\n      expect(f(5)).toBe('no');\n      expect(f(10.123)).toBe('no');\n      expect(f(-10.123)).toBe('yes');\n      expect(f(-Infinity)).toBe('yes');\n    });\n  });\n});\n"
  },
  {
    "path": "tests/objects.test.ts",
    "content": "import { isMatching, match, P } from '../src';\nimport { Equal, Expect } from '../src/types/helpers';\n\ndescribe('Objects', () => {\n  describe('symbols', () => {\n    const symbolA = Symbol('symbol-a');\n    const symbolB = Symbol('symbol-b');\n    const symbolC = Symbol('symbol-c');\n    type Input = { [symbolA]: { [symbolB]: 'foo' | 'bar' } };\n\n    it('should work with symbols', () => {\n      const fn1 = (obj: Input) => {\n        if (isMatching({ [symbolA]: { [symbolB]: 'foo' } }, obj)) {\n          const value = obj[symbolA][symbolB];\n          type t = Expect<Equal<typeof value, 'foo'>>;\n        } else {\n          throw new Error('Expected obj to match the foo pattern!');\n        }\n      };\n\n      const fn2 = (obj: Input) => {\n        if (isMatching({ [symbolA]: { [symbolB]: 'bar' } }, obj)) {\n          const value = obj[symbolA][symbolB];\n          type t = Expect<Equal<typeof value, 'bar'>>;\n          throw new Error('Expected obj to not match the bar pattern!');\n        }\n      };\n\n      fn1({\n        [symbolA]: { [symbolB]: 'foo' },\n      });\n\n      fn2({\n        [symbolA]: { [symbolB]: 'foo' },\n      });\n    });\n\n    it('narrowing inference should work', () => {\n      const fn1 = (input: Input) => {\n        return match(input)\n          .with({ [symbolA]: P.select() }, (sel) => {\n            type t = Expect<Equal<typeof sel, { [symbolB]: 'foo' | 'bar' }>>;\n            return sel;\n          })\n          .exhaustive();\n      };\n\n      expect(fn1({ [symbolA]: { [symbolB]: 'bar' } })).toEqual({\n        [symbolB]: 'bar',\n      });\n\n      const fn2 = (input: Input | { [symbolC]: string }) => {\n        return match(input)\n          .with({ [symbolA]: P.any }, (sel) => {\n            type t = Expect<Equal<typeof sel, Input>>;\n            return sel;\n          })\n          .with({ [symbolC]: P.select() }, (x) => x)\n          .exhaustive();\n      };\n\n      expect(fn2({ [symbolC]: 'Hey' })).toEqual('Hey');\n    });\n\n    it('exhaustiveness checking should work', () => {\n      const fn1 = (input: Input | { [symbolC]: string }) => {\n        return match(input)\n          .with({ [symbolA]: P.any }, (sel) => {\n            type t = Expect<Equal<typeof sel, Input>>;\n            return sel;\n          })\n          .with({ [symbolC]: P.any }, () => '2')\n          .exhaustive();\n      };\n\n      const fn2 = (input: Input | { [symbolC]: string }) => {\n        return (\n          match(input)\n            .with({ [symbolA]: P.any }, (sel) => {\n              type t = Expect<Equal<typeof sel, Input>>;\n              return sel;\n            })\n            // @ts-expect-error\n            .exhaustive()\n        );\n      };\n    });\n  });\n});\n\ndescribe('Records ({})', () => {\n  it('Should match records', () => {\n    type Vector1 = { x: number };\n    type Vector2 = { x: number; y: number };\n    type Vector3 = {\n      x: number;\n      y: number;\n      z: number;\n    };\n    type Vector = Vector1 | Vector2 | Vector3;\n\n    const vector: Vector = { x: 1 };\n\n    expect(\n      match<Vector, string>(vector)\n        .with({ x: 1, y: 1, z: 1 }, (x) => {\n          type t = Expect<Equal<typeof x, { x: 1; y: 1; z: 1 }>>;\n          return 'vector3';\n        })\n        .with({ x: 2, y: 1 }, (x) => {\n          type t = Expect<\n            Equal<typeof x, { x: 2; y: 1 } | { z: number; x: 2; y: 1 }>\n          >;\n          return 'vector2';\n        })\n        .with({ x: 1 }, (x) => {\n          type t = Expect<\n            Equal<\n              typeof x,\n              { x: 1 } | { x: 1; y: number } | { x: 1; y: number; z: number }\n            >\n          >;\n          return 'vector1';\n        })\n        .otherwise(() => 'no match')\n    ).toEqual('vector1');\n  });\n});\n"
  },
  {
    "path": "tests/optional-props.test.ts",
    "content": "import { Expect, Equal } from '../src/types/helpers';\nimport { match, P } from '../src';\n\ndescribe('optional properties', () => {\n  it('matching on optional properties should work', () => {\n    type Post = {\n      type: 'post';\n      id?: number;\n      body: string;\n    };\n\n    const res = match<Post>({\n      type: 'post',\n      id: 2,\n      body: 'az',\n    })\n      .with({ type: 'post', id: 2 as const }, (x) => {\n        type t = Expect<Equal<typeof x, { type: 'post'; id: 2; body: string }>>;\n        return 100;\n      })\n      .with({ type: 'post', id: P.number }, (x) => {\n        type t = Expect<\n          Equal<typeof x, { type: 'post'; id: number; body: string }>\n        >;\n        return 10;\n      })\n      .with({ type: 'post' }, (x) => {\n        type t = Expect<Equal<typeof x, Post>>;\n        // id is still nullable\n        x.id = undefined;\n        return 1;\n      })\n      .run();\n\n    expect(res).toEqual(100);\n  });\n\n  it('should correctly narrow the input type when the input is assignable to the pattern type', () => {\n    type Foo =\n      | { type: 'test'; id?: string }\n      | { type: 'test2'; id?: string; otherProp: string }\n      | { type: 'test3'; id?: string; otherProp?: string };\n\n    const f = (foo: Foo) =>\n      match(foo)\n        .with({ type: 'test', id: P.not(undefined) }, ({ id }) => {\n          type t = Expect<Equal<typeof id, string>>;\n          return 0;\n        })\n\n        .with({ type: 'test' }, ({ id }) => {\n          type t = Expect<Equal<typeof id, string | undefined>>;\n          return 1;\n        })\n\n        .with({ type: 'test2' }, ({ id }) => {\n          type t = Expect<Equal<typeof id, string | undefined>>;\n          return 2;\n        })\n        .with({ type: 'test3' }, ({ id }) => {\n          type t = Expect<Equal<typeof id, string | undefined>>;\n          return 3;\n        })\n        .exhaustive();\n\n    expect(f({ type: 'test', id: '1' })).toEqual(0);\n    expect(f({ type: 'test' })).toEqual(1);\n    expect(f({ type: 'test2', otherProp: '' })).toEqual(2);\n    expect(f({ type: 'test3' })).toEqual(3);\n  });\n\n  it('issue #142: When pattern matching on an optional property, other optional properties should remain on the object', () => {\n    enum SomeEnum {\n      Foo = 'Foo',\n      Bar = 'Bar',\n    }\n\n    type SomeObject = {\n      a?: SomeEnum;\n      b?: string;\n      c?: boolean;\n    };\n\n    const input = {\n      a: SomeEnum.Foo,\n      b: 'not important',\n    } as SomeObject;\n\n    const result = match(input)\n      .with({ a: SomeEnum.Foo }, (value) => {\n        type t = Expect<\n          Equal<\n            typeof value,\n            {\n              a: SomeEnum.Foo;\n              b?: string | undefined;\n              c?: boolean | undefined;\n            }\n          >\n        >;\n        return `Foo: ${value.b}`;\n      })\n      .with({ a: SomeEnum.Bar }, (value) => `Bar: ${value.b}`)\n      .with({ a: P.optional(undefined) }, (value) => `<undefined>: ${value.b}`)\n      .exhaustive();\n\n    expect(result).toEqual(`Foo: not important`);\n  });\n});\n"
  },
  {
    "path": "tests/optional.test.ts",
    "content": "import { match, P } from '../src';\nimport { Equal, Expect } from '../src/types/helpers';\n\ndescribe('optional', () => {\n  it('should match even if the sub pattern is undefined', () => {\n    type Input = { a?: 'cool' } | { b: 'lol' };\n\n    const f = (input: Input) =>\n      match(input)\n        .with({ b: 'lol' }, (x) => {\n          return false;\n        })\n        .with({ a: P.optional('cool') }, (x) => {\n          type t = Expect<Equal<typeof x, { a?: 'cool' | undefined }>>;\n          return true;\n        })\n        .exhaustive();\n\n    expect(f({})).toBe(true);\n    expect(f({ a: 'cool' })).toBe(true);\n    expect(f({ b: 'lol' })).toBe(false);\n  });\n\n  it('should support a nested pattern', () => {\n    type Input = { a?: { name: string; age: number } } | { b: '' };\n\n    const f = (input: Input) =>\n      match<Input>(input)\n        .with({ a: P.optional({ name: 'Hello' }) }, (x) => {\n          type t = Expect<\n            Equal<typeof x, { a?: { name: 'Hello'; age: number } }>\n          >;\n          return true;\n        })\n        .with({ b: P.string }, (x) => {\n          return false;\n        })\n        .with({ a: { name: P.string } }, () => false)\n        .exhaustive();\n\n    // Not Hello\n    expect(f({ a: { name: 'Bonjour', age: 20 } })).toBe(false);\n    expect(f({ a: { name: 'Hello', age: 20 } })).toBe(true);\n    expect(f({})).toBe(true);\n  });\n\n  it('should support anonymous select', () => {\n    type Input =\n      | { type: 'a'; a?: { name: string; age: number } }\n      | { type: 'b'; b?: 'test' };\n\n    const input = { type: 'b' } as Input;\n\n    match(input).with(\n      { type: 'a', a: P.optional({ name: P.select() }) },\n      (x) => {\n        type t = Expect<Equal<typeof x, string | undefined>>;\n        return x;\n      }\n    );\n\n    match(input).with({ type: 'a', a: P.select().optional() }, (x) => {\n      type t = Expect<\n        Equal<typeof x, { name: string; age: number } | undefined>\n      >;\n      return x;\n    });\n\n    match(input).with(\n      { type: 'b', b: P.select(P.optional(P.union('test'))) },\n      (x) => {\n        type t = Expect<Equal<typeof x, 'test' | undefined>>;\n        return x;\n      }\n    );\n\n    match(input).with({ a: P.not(undefined) }, (x) => {\n      type t = Expect<\n        Equal<\n          typeof x,\n          {\n            type: 'a';\n            a: {\n              name: string;\n              age: number;\n            };\n          }\n        >\n      >;\n      return '1';\n    });\n\n    const f = (input: Input) =>\n      match(input)\n        .with({ type: 'a', a: P.optional({ name: P.select() }) }, (x) => {\n          type t = Expect<Equal<typeof x, string | undefined>>;\n          return x;\n        })\n        .with({ type: 'b', b: P.optional(P.select(P.union('test'))) }, (x) => {\n          type t = Expect<Equal<typeof x, 'test' | undefined>>;\n          return x;\n        })\n        .exhaustive();\n\n    expect(f({ type: 'a' })).toBe(undefined);\n    expect(f({ type: 'b', b: 'test' })).toBe('test');\n  });\n\n  it('should support named select', () => {\n    type Input = { a?: { name: string; age: number } } | { b: 'b' };\n\n    expect(\n      match<Input>({})\n        .with(\n          {\n            a: P.optional({ name: P.select('name'), age: P.select('age') }),\n          },\n          ({ name, age }) => {\n            type t1 = Expect<Equal<typeof name, string | undefined>>;\n            type t2 = Expect<Equal<typeof age, number | undefined>>;\n            return name;\n          }\n        )\n        .with({ b: 'b' }, (x) => {\n          return '1';\n        })\n        .exhaustive()\n    ).toBe(undefined);\n  });\n\n  it('should support named select', () => {\n    type Input =\n      | {\n          type: 'a';\n          data?: { type: 'img'; src: string } | { type: 'text'; p: string };\n        }\n      | {\n          type: 'b';\n          data?: { type: 'video'; src: number } | { type: 'gif'; p: string };\n        };\n\n    expect(\n      match<Input>({ type: 'a', data: { type: 'text', p: 'paragraph' } })\n        .with(\n          {\n            type: 'a',\n            data: P.optional({ type: 'img' }),\n          },\n          (x) => {\n            type t = Expect<\n              Equal<\n                typeof x,\n                { type: 'a'; data?: { type: 'img'; src: string } | undefined }\n              >\n            >;\n\n            return x;\n          }\n        )\n        .with(\n          {\n            type: 'a',\n            data: P.optional({ type: 'text', p: P.select('p') }),\n          },\n          (x) => {\n            type t = Expect<Equal<typeof x, { p: string | undefined }>>;\n            return x.p;\n          }\n        )\n        .with(\n          {\n            type: 'b',\n            data: P.optional({ type: 'video', src: P.select('src') }),\n          },\n          ({ src }) => {\n            type t = Expect<Equal<typeof src, number | undefined>>;\n            return src;\n          }\n        )\n        .with(\n          {\n            type: 'b',\n            data: P.optional({ type: 'gif', p: P.select('p') }),\n          },\n          ({ p }) => {\n            type t = Expect<Equal<typeof p, string | undefined>>;\n            return p;\n          }\n        )\n        .exhaustive()\n    ).toBe('paragraph');\n  });\n\n  it('should support list patterns', () => {\n    type Input = { maybeList?: { text: string }[] };\n\n    const f = (input: Input) =>\n      match(input)\n        .with({ maybeList: P.optional(P.array({ text: P.select() })) }, (x) => {\n          type t = Expect<Equal<typeof x, string[] | undefined>>;\n          return x;\n        })\n        .exhaustive();\n\n    expect(f({})).toBe(undefined);\n    expect(f({ maybeList: [{ text: 'Hello' }, { text: 'Bonjour' }] })).toEqual([\n      'Hello',\n      'Bonjour',\n    ]);\n  });\n});\n"
  },
  {
    "path": "tests/otherwise.test.ts",
    "content": "import { match } from '../src';\n\ndescribe('otherwise', () => {\n  it('should pass matched value to otherwise', () => {\n    const result = match<number>(42)\n      .with(51, (d) => d)\n      .otherwise((d) => d);\n    expect(result).toBe(42);\n  });\n});\n"
  },
  {
    "path": "tests/output-type.test.ts",
    "content": "import { match, P } from '../src';\nimport { Equal, Expect } from '../src/types/helpers';\nimport { State } from './types-catalog/utils';\n\ndescribe('output type', () => {\n  describe('exhaustive', () => {\n    it('should return a single type if they are all compatible', () => {\n      const f = (input: number) =>\n        match(input)\n          .with(1, () => 'ok')\n          .with(2, () => 'test')\n          .with(P._, () => 'hello')\n          .exhaustive();\n\n      type o1 = Expect<Equal<ReturnType<typeof f>, string>>;\n\n      const f2 = (input: number) =>\n        match(input)\n          .with(1, () => ({ x: 'ok' }))\n          .with(2, () => ({ x: 'test' }))\n          .with(P._, () => ({ x: 'hello' }))\n          .exhaustive();\n\n      type o2 = Expect<Equal<ReturnType<typeof f2>, { x: string }>>;\n\n      const f3 = (input: number) =>\n        match(input)\n          .with(1, () => [1, 2, null])\n          .with(3, () => [1, 2])\n          .with(P._, () => [null, null])\n          .exhaustive();\n\n      type o3 = Expect<Equal<ReturnType<typeof f3>, (number | null)[]>>;\n    });\n\n    it('if the current inferred output is assignable to the new output, just pick the broader one', () => {\n      const f1 = (input: number) =>\n        match(input)\n          .with(1, () => [1, 2])\n          .with(P._, () => [1, 2, null])\n          .exhaustive();\n\n      type o1 = Expect<Equal<ReturnType<typeof f1>, (number | null)[]>>;\n    });\n\n    it('It should still be possible specify a precise output type', () => {\n      const f1 = (input: number) =>\n        match<number, State>(input)\n          .with(P._, () => ({ status: 'idle' }))\n          // @ts-expect-error\n          .with(1, () => [1, 2])\n          // @ts-expect-error\n          .with(P._, () => [1, 2, null])\n          .exhaustive();\n\n      type o1 = Expect<Equal<ReturnType<typeof f1>, State>>;\n    });\n  });\n\n  describe('run', () => {\n    it('should return a single type if they are all compatible', () => {\n      const f = (input: number) =>\n        match(input)\n          .with(1, () => 'ok')\n          .with(2, () => 'test')\n          .with(P._, () => 'hello')\n          .run();\n\n      type o1 = Expect<Equal<ReturnType<typeof f>, string>>;\n\n      const f2 = (input: number) =>\n        match(input)\n          .with(1, () => ({ x: 'ok' }))\n          .with(2, () => ({ x: 'test' }))\n          .with(P._, () => ({ x: 'hello' }))\n          .run();\n\n      type o2 = Expect<Equal<ReturnType<typeof f2>, { x: string }>>;\n\n      const f3 = (input: number) =>\n        match(input)\n          .with(1, () => [1, 2, null])\n          .with(3, () => [1, 2])\n          .with(P._, () => [null, null])\n          .run();\n\n      type o3 = Expect<Equal<ReturnType<typeof f3>, (number | null)[]>>;\n    });\n\n    it('if the current inferred output is assignable to the new output, just pick the broader one', () => {\n      const f1 = (input: number) =>\n        match(input)\n          .with(1, () => [1, 2])\n          .with(P._, () => [1, 2, null])\n          .run();\n\n      type o1 = Expect<Equal<ReturnType<typeof f1>, (number | null)[]>>;\n    });\n\n    it('It should still be possible specify a precise output type', () => {\n      const f1 = (input: number) =>\n        match<number, State>(input)\n          .with(P._, () => ({ status: 'idle' }))\n          // @ts-expect-error\n          .with(1, () => [1, 2])\n          // @ts-expect-error\n          .with(P._, () => [1, 2, null])\n          .run();\n\n      type o1 = Expect<Equal<ReturnType<typeof f1>, State>>;\n    });\n  });\n\n  describe('otherwise', () => {\n    it('should return a single type if they are all compatible', () => {\n      const f = (input: number) =>\n        match(input)\n          .with(1, () => 'ok')\n          .with(2, () => 'test')\n          .with(P._, () => 'hello')\n          .otherwise(() => '');\n\n      type o1 = Expect<Equal<ReturnType<typeof f>, string>>;\n\n      const f2 = (input: number) =>\n        match(input)\n          .with(1, () => ({ x: 'ok' }))\n          .with(2, () => ({ x: 'test' }))\n          .with(P._, () => ({ x: 'hello' }))\n          .otherwise(() => ({ x: '' }));\n\n      type o2 = Expect<Equal<ReturnType<typeof f2>, { x: string }>>;\n\n      const f3 = (input: number) =>\n        match(input)\n          .with(1, () => [1, 2, null])\n          .with(3, () => [1, 2])\n          .with(P._, () => [null, null])\n          .otherwise(() => [0]);\n\n      type o3 = Expect<Equal<ReturnType<typeof f3>, (number | null)[]>>;\n    });\n\n    it('if the current inferred output is assignable to the new output, just pick the broader one', () => {\n      const f1 = (input: number) =>\n        match(input)\n          .with(1, () => [1, 2])\n          .with(P._, () => [1, 2, null])\n          .otherwise(() => [0]);\n\n      type o1 = Expect<Equal<ReturnType<typeof f1>, (number | null)[]>>;\n    });\n\n    it('It should still be possible specify a precise output type', () => {\n      const f1 = (input: number) =>\n        match<number, State>(input)\n          .with(P._, () => ({ status: 'idle' }))\n          // @ts-expect-error\n          .with(1, () => [1, 2])\n          // @ts-expect-error\n          .with(P._, () => [1, 2, null])\n          .otherwise(() => ({ status: 'idle' }));\n\n      type o1 = Expect<Equal<ReturnType<typeof f1>, State>>;\n    });\n  });\n});\n"
  },
  {
    "path": "tests/pattern.test.ts",
    "content": "import { P } from '../src';\nimport { Equal, Expect } from '../src/types/helpers';\nimport { Matcher } from '../src/types/Pattern';\n\ntype ExtendsPattern<a, p extends P.Pattern<a>> = true;\n\ndescribe('Pattern', () => {\n  it(\"shouldn't allow invalid patterns\", () => {\n    type cases = [\n      ExtendsPattern<\n        { type: 'a'; x: { y: string } } | { type: 'b' },\n        { type: 'a'; x: { y: Matcher<unknown, string> } }\n      >\n    ];\n  });\n\n  it('Should return a single object pattern when the input is a union of objects', () => {\n    type res1 = P.Pattern<{ kind: 'some'; value: number } | { kind: 'none' }>;\n\n    type test1 = Expect<\n      Equal<\n        res1,\n        | Matcher<\n            { kind: 'some'; value: number } | { kind: 'none' },\n            unknown,\n            any,\n            any,\n            unknown\n          >\n        | {\n            readonly kind?: P.Pattern<'some' | 'none'>;\n            readonly value?: P.Pattern<number>;\n          }\n      >\n    >;\n  });\n\n  it('Should return a single object pattern when the input is a union of objects and other types', () => {\n    type t = P.Pattern<\n      { kind: 'some'; value: number } | { kind: 'none' } | string\n    >;\n\n    type t1 = Expect<\n      Equal<\n        P.Pattern<{ kind: 'some'; value: number } | { kind: 'none' } | string>,\n        | Matcher<\n            string | { kind: 'some'; value: number } | { kind: 'none' },\n            unknown,\n            any,\n            any,\n            unknown\n          >\n        | {\n            readonly kind?: P.Pattern<'some' | 'none'>;\n            readonly value?: P.Pattern<number>;\n          }\n        | string\n      >\n    >;\n\n    type t2 = Expect<\n      Equal<\n        P.Pattern<{ a?: { name: string; age: number } } | { b: '' }>,\n        | Matcher<\n            { a?: { name: string; age: number } } | { b: '' },\n            unknown,\n            any,\n            any,\n            unknown\n          >\n        | {\n            readonly a?: P.Pattern<{ name: string; age: number }>;\n            readonly b?: P.Pattern<''>;\n          }\n      >\n    >;\n    type t3 = Expect<\n      Equal<\n        P.Pattern<{ name: string; age: number } | undefined>,\n        | Matcher<\n            { name: string; age: number } | undefined,\n            unknown,\n            any,\n            any,\n            unknown\n          >\n        | {\n            readonly name?: P.Pattern<string>;\n            readonly age?: P.Pattern<number>;\n          }\n        | undefined\n      >\n    >;\n\n    type res4 = P.Pattern<{ name: string; age: number } | [type: 'Hello']>;\n\n    type t4 = Expect<\n      Equal<\n        res4,\n        | Matcher<\n            { name: string; age: number } | [type: 'Hello'],\n            unknown,\n            any,\n            any,\n            unknown\n          >\n        | {\n            readonly name?: P.Pattern<string>;\n            readonly age?: P.Pattern<number>;\n          }\n        | readonly [type: P.Pattern<'Hello'>]\n      >\n    >;\n  });\n});\n"
  },
  {
    "path": "tests/primitive-values.test.ts",
    "content": "import { match, P } from '../src';\nimport { Equal, Expect } from '../src/types/helpers';\n\ndescribe('Primitive values', () => {\n  it('patterns can be any literal value', () => {\n    const x = 2 as unknown;\n\n    expect(\n      match(x)\n        .with(true, (x) => {\n          type t = Expect<Equal<typeof x, true>>;\n          return 'true';\n        })\n        .with(false, (x) => {\n          type t = Expect<Equal<typeof x, false>>;\n          return 'false';\n        })\n        .with(null, (x) => {\n          type t = Expect<Equal<typeof x, null>>;\n          return 'null';\n        })\n        .with(undefined, (x) => {\n          type t = Expect<Equal<typeof x, undefined>>;\n          return 'undefined';\n        })\n        .with(Symbol.for('Hello'), (x) => {\n          type t = Expect<Equal<typeof x, symbol>>;\n          return 'Symbol';\n        })\n        .with('hello', (x) => {\n          type t = Expect<Equal<typeof x, 'hello'>>;\n          return 'hello';\n        })\n        .with(1, (x) => {\n          type t = Expect<Equal<typeof x, 1>>;\n          return '1';\n        })\n        .with(BigInt(2000), (x) => {\n          type t = Expect<Equal<typeof x, bigint>>;\n          return 'BigInt(2000)';\n        })\n        .with(2, (x) => {\n          type t = Expect<Equal<typeof x, 2>>;\n          return '2';\n        })\n        .otherwise(() => '?')\n    ).toEqual('2');\n  });\n\n  it('primitive patterns should correctly narrow the value', () => {\n    const f = (x: unknown) =>\n      match(x)\n        .with(P.boolean, (x) => {\n          type t = Expect<Equal<typeof x, boolean>>;\n          return 'boolean';\n        })\n        .with(P.nullish, (x) => {\n          type t = Expect<Equal<typeof x, null | undefined>>;\n          return 'nullish';\n        })\n        .with(P.symbol, (x) => {\n          type t = Expect<Equal<typeof x, symbol>>;\n          return 'symbol';\n        })\n        .with(P.string, (x) => {\n          type t = Expect<Equal<typeof x, string>>;\n          return 'string';\n        })\n        .with(P.number, (x) => {\n          type t = Expect<Equal<typeof x, number>>;\n          return 'number';\n        })\n        .with(P.bigint, (x) => {\n          type t = Expect<Equal<typeof x, bigint>>;\n          return 'bigint';\n        })\n        .otherwise(() => '?');\n\n    expect(f(true)).toEqual('boolean');\n    expect(f(null)).toEqual('nullish');\n    expect(f(Symbol('hello'))).toEqual('symbol');\n    expect(f('hello')).toEqual('string');\n    expect(f(20)).toEqual('number');\n    expect(f(BigInt(100))).toEqual('bigint');\n  });\n});\n"
  },
  {
    "path": "tests/readonly.test.ts",
    "content": "import { P, match } from '../src';\nimport { Equal, Expect } from '../src/types/helpers';\n\ndescribe('readonly', () => {\n  describe('exhaustive', () => {\n    it('tuples', () => {\n      const f = (input: readonly ['a' | 'b', 'c' | 'd']) =>\n        match(input)\n          .with(['a', 'c'], (x) => {\n            type t = Expect<Equal<typeof x, readonly ['a', 'c']>>;\n            return 'ok';\n          })\n          .with(['a', 'd'], (x) => {\n            type t = Expect<Equal<typeof x, readonly ['a', 'd']>>;\n            return 'ok';\n          })\n          .with(['b', 'c'], (x) => {\n            type t = Expect<Equal<typeof x, readonly ['b', 'c']>>;\n            return 'ok';\n          })\n          .with(['b', 'd'], (x) => {\n            type t = Expect<Equal<typeof x, readonly ['b', 'd']>>;\n            return 'ok';\n          })\n          .exhaustive();\n    });\n\n    it('objects', () => {\n      const f = (\n        input: Readonly<{ t: 'a'; x: number }> | Readonly<{ t: 'b'; x: string }>\n      ) =>\n        match(input)\n          .with({ t: 'a' }, (x) => {\n            type t = Expect<Equal<typeof x, Readonly<{ t: 'a'; x: number }>>>;\n            return 'ok';\n          })\n          .with({ t: 'b' }, (x) => {\n            type t = Expect<Equal<typeof x, Readonly<{ t: 'b'; x: string }>>>;\n            return 'ok';\n          })\n          .exhaustive();\n    });\n\n    it('mixed', () => {\n      const f = (\n        input:\n          | Readonly<{ t: 'a'; x: readonly [number, string, 2] }>\n          | Readonly<{ t: 'b'; x: string }>\n      ) =>\n        match(input)\n          .with({ t: 'a', x: [2, 'hello', 2] }, (x) => {\n            type t = Expect<Equal<typeof x, { t: 'a'; x: [2, 'hello', 2] }>>;\n            return 'ok';\n          })\n          .with({ t: 'a', x: [2, 'hello', 2] as const }, (x) => {\n            type t = Expect<Equal<typeof x, { t: 'a'; x: [2, 'hello', 2] }>>;\n            return 'ok';\n          })\n          .with({ t: 'a' }, (x) => {\n            type t = Expect<\n              Equal<\n                typeof x,\n                Readonly<{ t: 'a'; x: readonly [number, string, 2] }>\n              >\n            >;\n            return 'ok';\n          })\n          .with({ t: 'b' }, (x) => {\n            type t = Expect<Equal<typeof x, Readonly<{ t: 'b'; x: string }>>>;\n            return 'ok';\n          })\n          .exhaustive();\n    });\n\n    it('must support exhaustive matching on readonly arrays', () => {\n      const sum = (xs: readonly number[]): number =>\n        match(xs)\n          .with([], (x) => {\n            type t = Expect<Equal<typeof x, readonly []>>;\n            return 0;\n          })\n          .with([P._, ...P.array()], ([x, ...xs]) => x + sum(xs))\n          .exhaustive();\n    });\n  });\n});\n"
  },
  {
    "path": "tests/real-world.test.ts",
    "content": "import { match, P } from '../src';\nimport { Equal, Expect } from '../src/types/helpers';\nimport { Definition } from './types-catalog/definition';\n\ndescribe('real world example of a complex input type', () => {\n  const f = (def: Definition) =>\n    match(def)\n      .with(\n        {\n          viz: 'timeseries',\n          requests: P.array({\n            queries: P.array(\n              P.union({ data_source: 'metrics', query: P.select() }, P.any)\n            ),\n          }),\n        },\n        (metricQueries) => {\n          type t = Expect<\n            Equal<typeof metricQueries, (string | undefined)[][]>\n          >;\n          return [`timeseries with metrics queries:`, metricQueries];\n        }\n      )\n      .with(\n        {\n          requests: [{ sql_query: P.select() }],\n          viz: 'wildcard',\n          specification: {\n            type: 'vega',\n          },\n        },\n        (q) => {\n          type t = Expect<Equal<typeof q, string>>;\n\n          return 'vega wildcard with sql_query: ' + q;\n        }\n      )\n      .with(\n        {\n          requests: P.array(\n            P.intersection(\n              P.union(\n                { response_format: 'timeseries' },\n                { response_format: 'scalar' }\n              ),\n              {\n                queries: P.array({ data_source: P.union('metrics', 'events') }),\n              }\n            )\n          ),\n        },\n        (x) => {\n          const format = x.requests[0]?.response_format;\n          const dataSource = x.requests[0]?.queries[0]?.data_source;\n          type t = Expect<Equal<typeof format, 'timeseries' | 'scalar'>>;\n          type t2 = Expect<Equal<typeof dataSource, 'metrics' | 'events'>>;\n\n          return [format, dataSource];\n        }\n      )\n      .with(\n        {\n          viz: P.union('timeseries', 'query_table'),\n          requests: [\n            {\n              // This works\n              queries: P.array({ data_source: P.union('metrics', 'events') }),\n              response_format: P.union('timeseries', 'scalar'),\n            },\n          ],\n        },\n        (x) => {}\n      )\n      .with(\n        {\n          viz: P.union('timeseries', 'query_table'),\n          requests: P.array({\n            response_format: P.union('timeseries', 'scalar'),\n          }),\n        },\n        () => 'formulas requests'\n      )\n      .with(\n        {\n          requests: P.array({ response_format: 'scalar' }),\n        },\n        () => 'formulas requests'\n      )\n      .with(\n        {\n          requests: P.array({ response_format: 'timeseries' }),\n        },\n        () => 'formulas requests'\n      )\n      .with(\n        {\n          requests: [{ response_format: P.union('timeseries', 'scalar') }],\n        },\n        () => 'formulas requests'\n      )\n      .with(\n        { style: P.optional({ palette_flip: true }) },\n        (withPalette) => withPalette.viz\n      )\n      .with(\n        { requests: P.array({ sql_query: P.select() }) },\n        (queries) => queries\n      )\n      .with(\n        { viz: 'geomap', requests: P.array({ response_format: P.select() }) },\n        (scalars) => scalars\n      )\n      .with(\n        {\n          viz: P.union(\n            'geomap',\n            'timeseries',\n            'heatmap',\n            'scatterplot',\n            'query_table'\n          ),\n        },\n        () => ''\n      )\n      .with(\n        { viz: 'servicemap' },\n        { viz: 'distribution' },\n        { viz: 'treemap' },\n        { viz: 'toplist' },\n        () => ''\n      )\n      .exhaustive();\n\n  it('should return the correct output', () => {\n    expect(\n      f({\n        viz: 'wildcard',\n        requests: [\n          {\n            sql_query: 'SELECT *',\n            request_type: 'sql',\n            response_format: 'scalar',\n          },\n        ],\n        specification: {\n          type: 'vega',\n          contents: { something: 'cool' },\n        },\n      })\n    ).toBe('vega wildcard with sql_query: SELECT *');\n\n    expect(\n      f({\n        viz: 'wildcard',\n        requests: [\n          {\n            sql_query: 'SELECT *',\n            request_type: 'sql',\n            response_format: 'scalar',\n          },\n        ],\n        specification: {\n          type: 'vega',\n          contents: { something: 'cool' },\n        },\n      })\n    ).toBe('vega wildcard with sql_query: SELECT *');\n\n    expect(\n      f({\n        viz: 'timeseries',\n        requests: [\n          {\n            response_format: 'timeseries',\n            queries: [\n              {\n                name: 'a',\n                data_source: 'metrics',\n                query: 'a',\n              },\n              {\n                name: 'b',\n                data_source: 'metrics',\n                query: 'b',\n              },\n              {\n                name: 'c',\n                data_source: 'logs',\n                compute: { aggregation: 'avg' },\n              },\n            ],\n          },\n          {\n            response_format: 'timeseries',\n            queries: [\n              {\n                name: 'd',\n                data_source: 'metrics',\n                query: 'd',\n              },\n            ],\n          },\n        ],\n      })\n    ).toEqual([\n      'timeseries with metrics queries:',\n      [['a', 'b', undefined], ['d']],\n    ]);\n  });\n});\n"
  },
  {
    "path": "tests/record.test.ts",
    "content": "import { Expect, Equal } from '../src/types/helpers';\nimport { match, P } from '../src';\n\ndescribe('P.record', () => {\n  it('should match any object when called with P.unknown', () => {\n    const input = { a: 1, b: 2 };\n\n    const result = match(input)\n      .with(P.record(P.unknown), () => 'matched object')\n      .otherwise(() => 'no match');\n\n    expect(result).toEqual('matched object');\n  });\n\n  it('should match empty objects', () => {\n    const input = {};\n\n    const result = match(input)\n      .with(P.record(P.string, P.number), () => 'matched')\n      .otherwise(() => 'no match');\n\n    expect(result).toEqual('matched');\n  });\n\n  it('should match Record<string, number> patterns', () => {\n    const userScores = {\n      alice: 100,\n      bob: 85,\n      charlie: 92,\n    };\n\n    const result = match<Record<string, number>>(userScores)\n      .with(P.record(P.string, P.number), (scores) => {\n        return 'all string keys with number values';\n      })\n      .otherwise(() => 'no match');\n\n    expect(result).toEqual('all string keys with number values');\n  });\n\n  it('should not match objects with incorrect key types', () => {\n    const mixedKeys: Record<string | number, string> = {\n      alice: 'developer',\n      [Symbol.for('answer')]: 'answer',\n    };\n\n    const result = match(mixedKeys)\n      .with(P.record(P.string, P.string), () => 'string keys only')\n      .with(P.record(P.union(P.string, P.symbol), P.string), () => 'mixed keys')\n      .otherwise(() => 'no match');\n\n    expect(result).toEqual('mixed keys');\n  });\n\n  it('should not match objects with incorrect value types', () => {\n    const mixedValues = {\n      a: 'string',\n      b: 42,\n      c: true,\n    };\n\n    const result = match(mixedValues)\n      .with(P.record(P.string, P.string), () => 'string values only')\n      .with(\n        P.record(P.string, P.union(P.string, P.number, P.boolean)),\n        () => 'mixed values'\n      )\n      .otherwise(() => 'no match');\n\n    expect(result).toEqual('mixed values');\n  });\n\n  it('should work with complex value patterns', () => {\n    const userProfiles: unknown = {\n      alice: { name: 'Alice', age: 25, active: true },\n      bob: { name: 'Bob', age: 30, active: false },\n    };\n\n    const result = match(userProfiles)\n      .with(\n        P.record(P.string, {\n          name: P.string,\n          age: P.number,\n          active: P.boolean,\n        }),\n        (profiles) => {\n          type t = Expect<\n            Equal<\n              typeof profiles,\n              Record<string, { name: string; age: number; active: boolean }>\n            >\n          >;\n          return 'user profiles';\n        }\n      )\n      .otherwise(() => 'no match');\n\n    expect(result).toEqual('user profiles');\n  });\n\n  it('should support basic selection patterns', () => {\n    const data = {\n      user1: { name: 'Alice' },\n      user2: { name: 'Bob' },\n    };\n\n    const result = match<Record<string, { name: string }>>(data)\n      .with(P.record(P.string, { name: P.string }), (records) => {\n        type t = Expect<\n          Equal<typeof records, Record<string, { name: string }>>\n        >;\n        return 'matched user records';\n      })\n      .otherwise(() => 'no match');\n\n    expect(result).toEqual('matched user records');\n  });\n\n  it('should not match null', () => {\n    const result = match(null)\n      .with(P.record(P.string, P.number), () => 'matched')\n      .otherwise(() => 'no match');\n\n    expect(result).toEqual('no match');\n  });\n\n  it('should not match arrays', () => {\n    const result = match(['a', 'b'])\n      .with(P.record(P.string, P.string), () => 'matched')\n      .otherwise(() => 'no match');\n\n    expect(result).toEqual('no match');\n  });\n\n  it('should not match primitives', () => {\n    const result = match('string')\n      .with(P.record(P.string, P.string), () => 'matched')\n      .otherwise(() => 'no match');\n\n    expect(result).toEqual('no match');\n  });\n\n  it('should not match objects with incorrect value types', () => {\n    const result = match({ a: 1, b: 2 })\n      .with(P.record(P.union(1, 2), P.number), () => 'matched')\n      .otherwise(() => 'no match');\n\n    expect(result).toEqual('no match');\n\n    const result2 = match({ a: 1, b: 2 })\n      .with(P.record(P.number, P.number), () => 'matched')\n      .otherwise(() => 'no match');\n\n    expect(result2).toEqual('no match');\n  });\n\n  it('should work with P.record().optional()', () => {\n    type Data = {\n      records?: Record<string, number>;\n    };\n\n    const data1: Data = { records: { a: 1, b: 2 } };\n    const data2: Data = {};\n\n    const matchResult = (input: Data) =>\n      match(input)\n        .with({ records: P.record(P.string, P.number).optional() }, (x) => {\n          type t = Expect<Equal<typeof x, Data>>;\n          return 'has records';\n        })\n        .otherwise(() => 'no records');\n\n    expect(matchResult(data1)).toEqual('has records');\n    expect(matchResult(data2)).toEqual('has records');\n  });\n\n  it('should work with numeric keys', () => {\n    const numericRecord: Record<number, string> = {\n      1: 'one',\n      2: 'two',\n      3: 'three',\n    };\n\n    const result = match(numericRecord)\n      .with(P.record(P.number, P.string), (value) => {\n        type t = Expect<Equal<typeof value, Record<number, string>>>;\n        return 'numeric keys';\n      })\n      .otherwise(() => 'no match');\n\n    expect(result).toEqual('numeric keys');\n  });\n\n  it('should throw error when given only one argument', () => {\n    expect(() => {\n      // Create a matcher that expects key and value but only gets key\n      const result = match({ a: 1 }).with(P.record(P.unknown), (value) => {\n        type t = Expect<Equal<typeof value, { readonly a: 1 }>>;\n        return 'matched';\n      });\n      return result;\n    }).toBeDefined(); // Just check this doesn't crash the compilation\n  });\n\n  it('should work with chaining methods', () => {\n    type OptionalRecord = {\n      data?: Record<string, number>;\n    };\n\n    const input1: OptionalRecord = { data: { a: 1, b: 2 } };\n    const input2: OptionalRecord = {};\n\n    const matchResult = (input: OptionalRecord) =>\n      match(input)\n        .with(\n          { data: P.record(P.string, P.union(1, 2)).optional() },\n          (value) => {\n            type t = Expect<\n              Equal<typeof value, { data?: Record<string, 1 | 2> }>\n            >;\n            return 'has data';\n          }\n        )\n        .otherwise(() => 'no data');\n\n    expect(matchResult(input1)).toEqual('has data');\n    expect(matchResult(input2)).toEqual('has data');\n  });\n\n  it('should handle complex nested patterns', () => {\n    const nestedData: unknown = {\n      users: {\n        alice: { profile: { name: 'Alice', age: 25 }, active: true },\n        bob: { profile: { name: 'Bob', age: 30 }, active: false },\n      },\n    };\n\n    const result = match(nestedData)\n      .with(\n        {\n          users: P.record(P.string, {\n            profile: { name: P.string, age: P.number },\n            active: P.boolean,\n          }),\n        },\n        (value) => {\n          type t = Expect<\n            Equal<\n              typeof value,\n              {\n                users: Record<\n                  string,\n                  { profile: { name: string; age: number }; active: boolean }\n                >;\n              }\n            >\n          >;\n          return 'complex nested match';\n        }\n      )\n      .otherwise(() => 'no match');\n\n    expect(result).toEqual('complex nested match');\n  });\n\n  it('should support symbol keys', () => {\n    const f = (input: unknown) =>\n      match(input)\n        .with(P.record(P.symbol, P.number), (value) => {\n          type t = Expect<Equal<typeof value, Record<symbol, number>>>;\n          return 'matched';\n        })\n        .otherwise(() => 'no match');\n\n    expect(f({ a: 1, b: 2 })).toEqual('no match');\n    expect(f({ [Symbol('a')]: 1, [Symbol('b')]: 2 })).toEqual('matched');\n  });\n\n  it('should be chainable', () => {\n    type Input = { key?: Record<string, number> };\n    const input: Input = { key: { a: 1, b: 2 } };\n    const result = match(input)\n      .with(\n        { key: P.record(P.string, P.number).optional().select() },\n        (value) => {\n          type t = Expect<\n            Equal<typeof value, Record<string, number> | undefined>\n          >;\n          return 'matched';\n        }\n      )\n      .otherwise(() => 'no match');\n\n    expect(result).toEqual('matched');\n  });\n\n  describe('numeric keys', () => {\n    it('should match numeric keys', () => {\n      const input: unknown = { 1: 'one', 2: 'two', 3: 'three' };\n      const result = match(input)\n        .with(P.record(P.number, P.string), (value) => {\n          type t = Expect<Equal<typeof value, Record<number, string>>>;\n          return 'matched';\n        })\n        .otherwise(() => 'no match');\n      expect(result).toEqual('matched');\n    });\n\n    it('should match with number literals', () => {\n      const input: unknown = { 1: 'one' };\n      const result = match(input)\n        .with(P.record(1, P.string), (value) => {\n          type t = Expect<Equal<typeof value, Record<1, string>>>;\n          return 'matched';\n        })\n        .otherwise(() => 'no match');\n      expect(result).toEqual('matched');\n    });\n\n    it('should match with unions of number literals', () => {\n      const input: unknown = { 1: 'one', 2: 'two' };\n      const result = match(input)\n        .with(P.record(P.union(1, 2), P.string), (value) => {\n          type t = Expect<Equal<typeof value, Record<1 | 2, string>>>;\n          return 'matched';\n        })\n        .otherwise(() => 'no match');\n      expect(result).toEqual('matched');\n    });\n\n    it('P.string should also match numeric keys', () => {\n      const input: unknown = { 1: 'one', 2: 'two' };\n      const result = match(input)\n        .with(P.record(P.string, P.string), (value) => {\n          type t = Expect<Equal<typeof value, Record<string, string>>>;\n          return 'matched';\n        })\n        .otherwise(() => 'no match');\n      expect(result).toEqual('matched');\n    });\n  });\n\n  describe('select', () => {\n    it('should select all keys as an array when select is used in the key position', () => {\n      const input: unknown = { a: 1, b: 2 };\n      const result = match(input)\n        .with(P.record(P.string.select(), P.number), (value) => {\n          type t = Expect<Equal<typeof value, string[]>>;\n          return value;\n        })\n        .otherwise(() => 'no match');\n\n      expect(result).toEqual(['a', 'b']);\n    });\n\n    it('should select all values as an array when select is used in the value position', () => {\n      const input: unknown = { a: 1, b: 2 };\n      const result = match(input)\n        .with(P.record(P.string, P.number.select()), (value) => {\n          type t = Expect<Equal<typeof value, number[]>>;\n          return value;\n        })\n        .otherwise(() => 'no match');\n\n      expect(result).toEqual([1, 2]);\n    });\n\n    it('should select arrays when select() is nested inside the record value pattern', () => {\n      const input: unknown = {\n        a: { name: { first: 'John', last: 'Doe' } },\n        b: { name: { first: 'Jane', last: 'Doe' } },\n      };\n      const result = match(input)\n        .with(\n          P.record(P.string, { name: { first: P.string.select() } }),\n          (value) => {\n            type t = Expect<Equal<typeof value, string[]>>;\n            return value;\n          }\n        )\n        .otherwise(() => 'no match');\n\n      expect(result).toEqual(['John', 'Jane']);\n    });\n  });\n\n  describe('type inference', () => {\n    it(\"shouldn't accept key patterns that aren't PropertyKey\", () => {\n      const input: unknown = { a: 1, b: 2 };\n      const result = match(input)\n        // @ts-expect-error 👇 error should be here\n        .with(P.record({}, P.number), (value) => {})\n        // FIXME: P.array(), etc are accepted, but shouldn't.\n        .with(P.record(P.array(), P.number), (value) => {})\n        .otherwise(() => 'no match');\n\n      expect(result).toEqual('no match');\n    });\n\n    it('should infer the correct type', () => {\n      const input: unknown = { a: 1, b: 2 };\n\n      match(input)\n        .with(P.record(P.string, P.union(1, 2)), (value) => {\n          type t = Expect<Equal<typeof value, Record<string, 1 | 2>>>;\n          return 'matched';\n        })\n        // or pattern\n        .with(P.record(P.string, P.union(1, 2)).or(123), (value) => {\n          type t = Expect<Equal<typeof value, Record<string, 1 | 2> | 123>>;\n          return 'matched';\n        })\n        // and pattern\n        .with(P.record(P.string, P.union(1, 2)).and({ a: 1 }), (value) => {\n          type t = Expect<\n            Equal<typeof value, Record<string, 1 | 2> & { a: 1 }>\n          >;\n          return 'matched';\n        })\n        // key pattern\n        .with(P.record(P.number, P.number), (value) => {\n          type t = Expect<Equal<typeof value, Record<number, number>>>;\n          return 'matched';\n        })\n        .with(P.record(P.union(1, 2, 3), P.number), (value) => {\n          type t = Expect<Equal<typeof value, Record<1 | 2 | 3, number>>>;\n          return 'matched';\n        })\n        // select a key\n        .with(P.record(P.number.select(), P.number), (value) => {\n          type t = Expect<Equal<typeof value, number[]>>;\n          return 'matched';\n        })\n        // select a value\n        .with(P.record(P.number, P.number.select()), (value) => {\n          type t = Expect<Equal<typeof value, number[]>>;\n          return 'matched';\n        })\n        // nested records\n        .with(P.record(P.number, P.record(P.string, P.number)), (value) => {\n          type t = Expect<\n            Equal<typeof value, Record<number, Record<string, number>>>\n          >;\n          return 'matched';\n        })\n        // nested records with select\n        .with(\n          P.record(P.number, P.record(P.string, P.number.select())),\n          (value) => {\n            type t = Expect<Equal<typeof value, number[][]>>;\n            return 'matched';\n          }\n        )\n        // optional modifier\n        .with(P.record(P.number, P.number).optional(), (value) => {\n          type t = Expect<\n            Equal<typeof value, Record<number, number> | undefined>\n          >;\n          return 'matched';\n        })\n        // arrays of records\n        .with(P.array(P.record(P.string, P.number)), (value) => {\n          type t = Expect<Equal<typeof value, Record<string, number>[]>>;\n          return 'matched';\n        })\n        // records of arrays\n        .with(P.record(P.string, P.array(P.number)), (value) => {\n          type t = Expect<Equal<typeof value, Record<string, number[]>>>;\n          return 'matched';\n        })\n        // tuple containing records\n        .with([P.record(P.string, P.number), P.number], (value) => {\n          type t = Expect<\n            Equal<typeof value, [Record<string, number>, number]>\n          >;\n          return 'matched';\n        })\n        .otherwise(() => 'no match');\n    });\n\n    it(\"shouldn't allow incorrect value types\", () => {\n      const input: Record<string, { name: string; age?: number }> = {\n        a: { name: 'John' },\n        b: { name: 'Jane' },\n      };\n      const result = match(input)\n        // if the pattern is correct, it should accept it\n        .with(\n          P.record(P.string, {\n            age: P.number,\n          }),\n          (value) => {\n            return 'matched';\n          }\n        )\n        .with(\n          P.record(P.string, {\n            // @ts-expect-error\n            firstName: P.string,\n          }),\n          (value) => {\n            return 'matched';\n          }\n        )\n\n        .otherwise(() => 'no match');\n\n      expect(result).toEqual('no match');\n    });\n\n    it(\"shouldn't allow incorrect key types\", () => {\n      const input: Record<number, number> = {\n        1: 1,\n        2: 2,\n      };\n\n      const result = match(input)\n        // @ts-expect-error\n        .with(P.record('1', P.number), (value) => {\n          return 'matched';\n        })\n        .otherwise(() => 'no match');\n    });\n\n    it('should exclude the correct types for exhaustive checking', () => {\n      // Test that P.record correctly excludes matched record types from exhaustive checking\n      type Input =\n        | { type: 'config'; data: Record<string, string> }\n        | { type: 'scores'; data: Record<string, number> }\n        | { type: 'flags'; data: Record<string, boolean> }\n        | { type: 'mixed'; data: Record<string, string | number> };\n\n      const input = { type: 'config', data: { theme: 'dark' } } as Input;\n\n      // Should not be exhaustive - missing other cases\n      match(input)\n        .with({ data: P.record(P.string, P.string) }, () => 'config')\n        // @ts-expect-error - not exhaustive, missing other cases\n        .exhaustive();\n\n      // Should not be exhaustive - missing 'flags' case\n      match(input)\n        .with({ data: P.record(P.string, P.string) }, () => 'config')\n        .with({ data: P.record(P.string, P.number) }, () => 'scores')\n        .with(\n          { data: P.record(P.string, P.union(P.string, P.number)) },\n          () => 'mixed'\n        )\n        // @ts-expect-error - not exhaustive, missing 'flags' case\n        .exhaustive();\n\n      // Should be exhaustive - all cases covered\n      match(input)\n        .with({ data: P.record(P.string, P.string) }, () => 'config')\n        .with({ data: P.record(P.string, P.number) }, () => 'scores')\n        .with({ data: P.record(P.string, P.boolean) }, () => 'flags')\n        .with(\n          { data: P.record(P.string, P.union(P.string, P.number)) },\n          () => 'mixed'\n        )\n        .exhaustive();\n\n      // Test with more complex record patterns using union keys\n      type ComplexInput =\n        | { kind: 'stringKeys'; data: Record<string, number> }\n        | { kind: 'numericKeys'; data: Record<number, string> }\n        | { kind: 'mixedKeys'; data: Record<string | number, boolean> };\n\n      const complexInput = {\n        kind: 'stringKeys',\n        data: { a: 1, b: 2 },\n      } as ComplexInput;\n\n      match(complexInput)\n        .with({ data: P.record(P.string, P.number) }, () => 'stringKeys')\n        .with({ data: P.record(P.number, P.string) }, () => 'numericKeys')\n        .with(\n          { data: P.record(P.union(P.string, P.number), P.boolean) },\n          () => 'mixedKeys'\n        )\n        .exhaustive();\n    });\n  });\n});\n"
  },
  {
    "path": "tests/return-type.test.ts",
    "content": "import { P, match } from '../src';\n\ndescribe('returnType', () => {\n  it('should only be allowed directly after match(...)', () => {\n    const f = (input: unknown) =>\n      match(input)\n        .returnType<string>() // allowed\n        .with(undefined, () => 'undefined')\n        .with(P.string, () => 'string')\n        .otherwise(() => 'unknown');\n\n    const f2 = (input: unknown) =>\n      match(input)\n        .with(undefined, () => 'undefined')\n        // @ts-expect-error: not allowed\n        .returnType<string>()\n        .with(P.string, () => 'string')\n        .otherwise(() => 'unknown');\n\n    const f3 = (input: unknown) =>\n      match(input)\n        .with(undefined, () => 'undefined')\n        .with(P.string, () => 'string')\n        // @ts-expect-error: not allowed\n        .returnType<string>()\n        .otherwise(() => 'unknown');\n  });\n\n  it('should restrict the return type to a specific type', () => {\n    const f = (input: string | undefined): string =>\n      match(input)\n        .returnType<string>()\n        // @ts-expect-error\n        .with(undefined, () => undefined)\n        .with(P.string, () => 'string')\n        // @ts-expect-error\n        .otherwise(() => true);\n  });\n\n  it('type errors should be well placed', () => {\n    match<null>(null)\n      .returnType<{ type: 'ok'; value: 'a' | 'b' }>()\n      .with(null, () => ({\n        type: 'ok',\n        // @ts-expect-error\n        value: 'oops',\n      }))\n      .exhaustive();\n  });\n});\n"
  },
  {
    "path": "tests/select.test.ts",
    "content": "import { Expect, Equal } from '../src/types/helpers';\nimport { match, P } from '../src';\nimport { State, Event } from './types-catalog/utils';\nimport {\n  MixedNamedAndAnonymousSelectError,\n  SeveralAnonymousSelectError,\n} from '../src/types/FindSelected';\n\ndescribe('select', () => {\n  it('should work with tuples', () => {\n    expect(\n      match<[string, number], number>(['get', 2])\n        .with(['get', P.select('y')], ({ y }) => {\n          type t = Expect<Equal<typeof y, number>>;\n          return y;\n        })\n        .run()\n    ).toEqual(2);\n  });\n\n  it('should work with array', () => {\n    expect(\n      match<string[], string[]>(['you', 'hello'])\n        .with([P.select('first')], ({ first }, xs) => {\n          type t = Expect<Equal<typeof xs, [string]>>;\n          type t2 = Expect<Equal<typeof first, string>>;\n          return [first];\n        })\n        .with(P.array(P.select('texts')), ({ texts }, xs) => {\n          type t = Expect<Equal<typeof xs, string[]>>;\n          type t2 = Expect<Equal<typeof texts, string[]>>;\n          return texts;\n        })\n        .run()\n    ).toEqual(['you', 'hello']);\n\n    expect(\n      match<{ text: string }[], string[]>([{ text: 'you' }, { text: 'hello' }])\n        .with(P.array({ text: P.select('texts') }), ({ texts }, xs) => {\n          type t = Expect<Equal<typeof xs, { text: string }[]>>;\n          type t2 = Expect<Equal<typeof texts, string[]>>;\n          return texts;\n        })\n        .run()\n    ).toEqual(['you', 'hello']);\n\n    expect(\n      match<{ text: { content: string } }[], string[]>([\n        { text: { content: 'you' } },\n        { text: { content: 'hello' } },\n      ])\n        .with(\n          P.array({ text: { content: P.select('texts') } }),\n          ({ texts }, xs) => {\n            type t = Expect<Equal<typeof texts, string[]>>;\n            return texts;\n          }\n        )\n        .run()\n    ).toEqual(['you', 'hello']);\n  });\n\n  it('should work with objects', () => {\n    expect(\n      match<State & { other: number }, string>({\n        status: 'success',\n        data: 'some data',\n        other: 20,\n      })\n        .with(\n          {\n            status: 'success',\n            data: P.select('data'),\n            other: P.select('other'),\n          },\n          ({ data, other }) => {\n            type t = Expect<Equal<typeof data, string>>;\n            type t2 = Expect<Equal<typeof other, number>>;\n            return data + other.toString();\n          }\n        )\n        .run()\n    ).toEqual('some data20');\n  });\n\n  it('should work with primitive types', () => {\n    expect(\n      match<string, string>('hello')\n        .with(P.select('x'), ({ x }) => {\n          type t = Expect<Equal<typeof x, string>>;\n          return x;\n        })\n        .run()\n    ).toEqual('hello');\n  });\n\n  it('should work with complex structures', () => {\n    const initState: State = {\n      status: 'idle',\n    };\n\n    const reducer = (state: State, event: Event): State =>\n      match<[State, Event], State>([state, event])\n        .with(\n          [\n            { status: 'loading' },\n            {\n              type: 'success',\n              data: P.select('data'),\n              requestTime: P.select('time'),\n            },\n          ],\n          ({ data, time }) => {\n            type t = Expect<Equal<typeof time, number | undefined>>;\n\n            return {\n              status: 'success',\n              data,\n            };\n          }\n        )\n        .with(\n          [{ status: 'loading' }, { type: 'success', data: P.select('data') }],\n          ({ data }) => ({\n            status: 'success',\n            data,\n          })\n        )\n        .with(\n          [{ status: 'loading' }, { type: 'error', error: P.select('error') }],\n          ({ error }) => ({\n            status: 'error',\n            error,\n          })\n        )\n        .with([{ status: 'loading' }, { type: 'cancel' }], () => initState)\n        .with([{ status: P.not('loading') }, { type: 'fetch' }], () => ({\n          status: 'loading',\n        }))\n        .with([P.select('state'), P.select('event')], ({ state, event }) => {\n          type t = Expect<Equal<typeof state, State>>;\n          type t2 = Expect<Equal<typeof event, Event>>;\n          return state;\n        })\n        .run();\n\n    expect(reducer(initState, { type: 'cancel' })).toEqual(initState);\n\n    expect(reducer(initState, { type: 'fetch' })).toEqual({\n      status: 'loading',\n    });\n\n    expect(\n      reducer({ status: 'loading' }, { type: 'success', data: 'yo' })\n    ).toEqual({\n      status: 'success',\n      data: 'yo',\n    });\n\n    expect(reducer({ status: 'loading' }, { type: 'cancel' })).toEqual({\n      status: 'idle',\n    });\n  });\n\n  it('should support nesting of several arrays', () => {\n    type Input = [{ name: string }, { post: { title: string }[] }][];\n    expect(\n      match<Input>([\n        [\n          { name: 'Gabriel' },\n          { post: [{ title: 'Hello World' }, { title: \"what's up\" }] },\n        ],\n        [{ name: 'Alice' }, { post: [{ title: 'Hola' }, { title: 'coucou' }] }],\n      ])\n        .with([], (x) => {\n          type t = Expect<Equal<typeof x, []>>;\n          return 'empty';\n        })\n        .with(\n          P.array([\n            { name: P.select('names') },\n            { post: P.array({ title: P.select('titles') }) },\n          ]),\n          ({ names, titles }) => {\n            type t = Expect<Equal<typeof names, string[]>>;\n            type t2 = Expect<Equal<typeof titles, string[][]>>;\n\n            return (\n              names.join(' and ') +\n              ' have written ' +\n              titles.map((t) => t.map((t) => `\"${t}\"`).join(', ')).join(', ')\n            );\n          }\n        )\n        .exhaustive()\n    ).toEqual(\n      `Gabriel and Alice have written \"Hello World\", \"what's up\", \"Hola\", \"coucou\"`\n    );\n  });\n\n  it('Anonymous selections should support nesting of several arrays', () => {\n    type Input = [{ name: string }, { post: { title: string }[] }][];\n    expect(\n      match<Input>([\n        [\n          { name: 'Gabriel' },\n          { post: [{ title: 'Hello World' }, { title: \"what's up\" }] },\n        ],\n        [{ name: 'Alice' }, { post: [{ title: 'Hola' }, { title: 'coucou' }] }],\n      ])\n        .with([], (x) => {\n          type t = Expect<Equal<typeof x, []>>;\n          return 'empty';\n        })\n        .with(\n          P.array([{ name: P.any }, { post: P.array({ title: P.select() }) }]),\n          (titles) => {\n            type t1 = Expect<Equal<typeof titles, string[][]>>;\n            return titles\n              .map((t) => t.map((t) => `\"${t}\"`).join(', '))\n              .join(', ');\n          }\n        )\n        .exhaustive()\n    ).toEqual(`\"Hello World\", \"what's up\", \"Hola\", \"coucou\"`);\n  });\n\n  it('should infer the selection to an error when using several anonymous selection', () => {\n    match({ type: 'point', x: 2, y: 3 })\n      .with({ type: 'point', x: P.select(), y: P.select() }, (x) => {\n        type t = Expect<Equal<typeof x, SeveralAnonymousSelectError>>;\n        return 'ok';\n      })\n      .run();\n  });\n\n  it('should infer the selection to an error when using mixed named and unnamed selections', () => {\n    match({ type: 'point', x: 2, y: 3 })\n      .with({ type: 'point', x: P.select(), y: P.select('y') }, (x) => {\n        type t = Expect<Equal<typeof x, MixedNamedAndAnonymousSelectError>>;\n        return 'ok';\n      })\n      .run();\n  });\n\n  describe('P.select with subpattern', () => {\n    type Input =\n      | {\n          type: 'a';\n          value:\n            | { type: 'img'; src: string }\n            | { type: 'text'; content: string; length: number };\n        }\n      | {\n          type: 'b';\n          value:\n            | { type: 'user'; username: string }\n            | { type: 'org'; orgId: number };\n        };\n\n    it('should support only selecting if the value matches a subpattern', () => {\n      const f = (input: Input) =>\n        match(input)\n          .with({ type: 'a', value: P.select({ type: 'img' }) }, (x) => {\n            type t = Expect<Equal<typeof x, { type: 'img'; src: string }>>;\n            return x.src;\n          })\n          .with(\n            { type: 'a', value: P.select('text', { type: 'text' }) },\n            (x) => {\n              type t = Expect<\n                Equal<\n                  typeof x,\n                  { text: { type: 'text'; content: string; length: number } }\n                >\n              >;\n              return x.text.content;\n            }\n          )\n          .with({ type: 'b', value: P.select({ type: 'user' }) }, (x) => {\n            type t = Expect<\n              Equal<typeof x, { type: 'user'; username: string }>\n            >;\n            return x.username;\n          })\n          .with({ type: 'b', value: P.select('org', { type: 'org' }) }, (x) => {\n            type t = Expect<\n              Equal<typeof x, { org: { type: 'org'; orgId: number } }>\n            >;\n            return x.org.orgId;\n          })\n          .exhaustive();\n\n      expect(f({ type: 'a', value: { type: 'img', src: 'Hello' } })).toEqual(\n        'Hello'\n      );\n\n      expect(\n        f({\n          type: 'a',\n          value: { type: 'text', length: 2, content: 'some text' },\n        })\n      ).toEqual('some text');\n\n      expect(\n        f({ type: 'b', value: { type: 'user', username: 'Gabriel' } })\n      ).toEqual('Gabriel');\n\n      expect(\n        f({\n          type: 'b',\n          value: { type: 'org', orgId: 2 },\n        })\n      ).toEqual(2);\n    });\n\n    it('should be possible to nest named selections', () => {\n      const f = (input: Input) =>\n        match(input)\n          .with(\n            {\n              type: 'a',\n              value: P.select('text', {\n                type: 'text',\n                content: P.select('content'),\n                length: P.select('length'),\n              }),\n            },\n            ({ text, content, length }) => {\n              type t1 = Expect<\n                Equal<\n                  typeof text,\n                  { type: 'text'; content: string; length: number }\n                >\n              >;\n              type t2 = Expect<Equal<typeof content, string>>;\n              type t3 = Expect<Equal<typeof length, number>>;\n              return [text, length, content];\n            }\n          )\n          .otherwise(() => null);\n\n      expect(\n        f({ type: 'a', value: { type: 'text', length: 2, content: 'yo' } })\n      ).toEqual([{ type: 'text', length: 2, content: 'yo' }, 2, 'yo']);\n\n      expect(f({ type: 'a', value: { type: 'img', src: 'yo' } })).toEqual(null);\n    });\n\n    it('should work with union subpatterns', () => {\n      type Input = {\n        value:\n          | { type: 'a'; v: string }\n          | { type: 'b'; v: number }\n          | { type: 'c'; v: boolean };\n      };\n\n      // select directly followed by union\n      const f = (input: Input) =>\n        match(input)\n          .with(\n            { value: P.select(P.union({ type: 'a' }, { type: 'b' })) },\n            (x) => {\n              type t = Expect<\n                Equal<\n                  typeof x,\n                  { type: 'a'; v: string } | { type: 'b'; v: number }\n                >\n              >;\n\n              return x.v;\n            }\n          )\n          .with({ value: { type: 'c' } }, () => 'c')\n          .exhaustive();\n\n      // select with an object that's a union by union\n      const f2 = (input: Input) =>\n        match(input)\n          .with({ value: P.select({ type: P.union('a', 'b') }) }, (x) => {\n            type t = Expect<\n              Equal<\n                typeof x,\n                { type: 'a'; v: string } | { type: 'b'; v: number }\n              >\n            >;\n\n            return x.v;\n          })\n          .with({ value: { type: 'c' } }, () => 'c')\n          .exhaustive();\n\n      expect(f({ value: { type: 'a', v: 'hello' } })).toEqual('hello');\n      expect(f2({ value: { type: 'a', v: 'hello' } })).toEqual('hello');\n\n      expect(f({ value: { type: 'b', v: 10 } })).toEqual(10);\n      expect(f2({ value: { type: 'b', v: 10 } })).toEqual(10);\n\n      expect(f({ value: { type: 'c', v: true } })).toEqual('c');\n      expect(f2({ value: { type: 'c', v: true } })).toEqual('c');\n    });\n\n    it('Should work with unions without discriminants', () => {\n      type Input =\n        | { type: 'a'; value: string }\n        | { type: 'b'; value: number }\n        | {\n            type: 'c';\n            value:\n              | { type: 'd'; value: boolean }\n              | { type: 'e'; value: string[] }\n              | { type: 'f'; value: number[] };\n          };\n\n      const f = (input: Input) =>\n        match(input)\n          .with({ type: P.union('a', 'b') }, (x) => {\n            return 'branch 1';\n          })\n          .with(\n            {\n              type: 'c',\n              value: { value: P.select(P.union(P.boolean, P.array(P.string))) },\n            },\n            (x) => {\n              type t = Expect<Equal<typeof x, boolean | string[]>>;\n              return 'branch 2';\n            }\n          )\n          .with({ type: 'c', value: { type: 'f' } }, () => 'branch 3')\n          .exhaustive();\n    });\n  });\n\n  it('Issue #95: P.select() on empty arrays should return an empty array', () => {\n    const res = match<{ a: string[]; b: string[] }>({ a: [], b: ['text'] })\n      .with(\n        { a: P.array(P.select('a')), b: P.array(P.select('b')) },\n        ({ a, b }) => {\n          type t = Expect<Equal<typeof a, string[]>>;\n          type t2 = Expect<Equal<typeof b, string[]>>;\n          return { a, b };\n        }\n      )\n      .otherwise(() => null);\n\n    expect(res).toEqual({ a: [], b: ['text'] });\n\n    // Should work with deeply nested selections as well\n    const res2 = match<{ a: { prop: number }[] }>({ a: [] })\n      .with({ a: P.array({ prop: P.select('a') }) }, ({ a }) => {\n        type t = Expect<Equal<typeof a, number[]>>;\n        return { a };\n      })\n      .otherwise(() => null);\n\n    expect(res2).toEqual({ a: [] });\n\n    // P.select of arrays shouldn't be affected\n    const res3 = match<{ a: { prop: number }[] }>({ a: [] })\n      .with({ a: P.select(P.array({ prop: P._ })) }, (a) => {\n        type t = Expect<Equal<typeof a, { prop: number }[]>>;\n        return { a };\n      })\n      .otherwise(() => null);\n\n    expect(res3).toEqual({ a: [] });\n  });\n\n  it('should work with variadic tuples', () => {\n    const fn = (input: string[]) =>\n      match(input)\n        .with(\n          [P.string, 'some', 'cli', 'cmd', P.select(), ...P.array()],\n          (arg) => {\n            type t = Expect<Equal<typeof arg, string>>;\n            return arg;\n          }\n        )\n        .otherwise(() => '2');\n\n    expect(fn(['some cli cmd param', 'some', 'cli', 'cmd', 'param'])).toEqual(\n      'param'\n    );\n    expect(\n      fn(['some cli cmd param --flag', 'some', 'cli', 'cmd', 'param', '--flag'])\n    ).toEqual('param');\n  });\n});\n"
  },
  {
    "path": "tests/sets.test.ts",
    "content": "import { Expect, Equal } from '../src/types/helpers';\nimport { match, P } from '../src';\n\ndescribe('Set', () => {\n  it('should match Set patterns', () => {\n    const containsGabAndYo = (set: Set<string | number>) =>\n      match<Set<string | number>, [boolean, boolean]>(set)\n        .with(P.set('gab'), (x) => {\n          type t = Expect<Equal<typeof x, Set<'gab'>>>;\n          return [true, false];\n        })\n        .with(P.set('yo'), (x) => {\n          type t = Expect<Equal<typeof x, Set<'yo'>>>;\n          return [false, true];\n        })\n        .with(P.set(P.union('gab', 'yo')), (x) => {\n          type t = Expect<Equal<typeof x, Set<'gab' | 'yo'>>>;\n          return [true, true];\n        })\n        .with(P._, (x) => {\n          type t = Expect<Equal<typeof x, Set<string | number>>>;\n          return [false, false];\n        })\n        .run();\n\n    expect(containsGabAndYo(new Set(['gab', 'yo']))).toEqual([true, true]);\n    expect(containsGabAndYo(new Set(['gab']))).toEqual([true, false]);\n    expect(containsGabAndYo(new Set(['yo']))).toEqual([false, true]);\n    expect(containsGabAndYo(new Set(['hello']))).toEqual([false, false]);\n    expect(containsGabAndYo(new Set([2]))).toEqual([false, false]);\n  });\n\n  it(\"should match any set if P.set isn't given any arguments\", () => {\n    const someSet = new Set([1, 2, 3]);\n\n    const res = match(someSet)\n      .with(P.set(), () => true)\n      .exhaustive();\n\n    type t = Expect<Equal<typeof res, boolean>>;\n\n    expect(res).toEqual(true);\n  });\n});\n"
  },
  {
    "path": "tests/strings.test.ts",
    "content": "import { P, match } from '../src';\nimport { Equal, Expect } from '../src/types/helpers';\n\ndescribe('Strings', () => {\n  it(`P.string.includes('str')`, () => {\n    const f = (input: string | number) =>\n      match(input)\n        .with(P.string.includes('!!'), (value) => {\n          type t = Expect<Equal<typeof value, string>>;\n          return 'includes !!';\n        })\n        .otherwise((value) => {\n          type t = Expect<Equal<typeof value, string | number>>;\n          return 'something else';\n        });\n\n    expect(f('hello!!')).toBe('includes !!');\n    expect(f('nope')).toBe('something else');\n  });\n\n  describe('startsWith', () => {\n    it(`P.string.startsWith('str')`, () => {\n      const f = (input: string | number) =>\n        match(input)\n          .with(P.string.startsWith('hello '), (value) => {\n            type t = Expect<Equal<typeof value, `hello ${string}`>>;\n            return 'starts with hello';\n          })\n          .otherwise((value) => {\n            type t = Expect<Equal<typeof value, string | number>>;\n            return 'something else';\n          });\n\n      expect(f('hello gabriel')).toBe('starts with hello');\n      expect(f('gabriel')).toBe('something else');\n    });\n\n    type FileFrom2022 = `2022-${number}-${number}`;\n    type FileFrom2023 = `2023-${number}-${number}`;\n\n    it('should narrow template literal types', () => {\n      const get = (x: FileFrom2022 | FileFrom2023): string =>\n        match(x)\n          .with(P.string.startsWith('2022-'), (x) => {\n            type t = Expect<Equal<typeof x, FileFrom2022>>;\n            return 'file from 2022';\n          })\n          .with(P.string.startsWith('2023-'), (x) => {\n            type t = Expect<Equal<typeof x, FileFrom2023>>;\n            return 'file from 2023';\n          })\n          .exhaustive();\n\n      expect(get('2022-04-01')).toEqual('file from 2022');\n      expect(get('2023-04-01')).toEqual('file from 2023');\n    });\n\n    it('should work as a nested pattern', () => {\n      type Input = { value: FileFrom2022 | FileFrom2023 };\n\n      const input: Input = { value: '2023-04-01' };\n\n      const output = match<Input>(input)\n        .with({ value: P.string.startsWith('2022-') }, (a) => {\n          type t = Expect<Equal<typeof a, { value: FileFrom2022 }>>;\n          return 'nested file from 2022';\n        })\n        .with({ value: P.string.startsWith('2023-') }, (b) => {\n          type t = Expect<Equal<typeof b, { value: FileFrom2023 }>>;\n          return 'nested file from 2023';\n        })\n        .exhaustive();\n\n      expect(output).toEqual('nested file from 2023');\n    });\n  });\n\n  it(`P.string.endsWith('str')`, () => {\n    const f = (input: string | number) =>\n      match(input)\n        .with(P.string.endsWith('!!'), (value) => {\n          type t = Expect<Equal<typeof value, `${string}!!`>>;\n          return 'ends with !!';\n        })\n        .otherwise((value) => {\n          type t = Expect<Equal<typeof value, string | number>>;\n          return 'something else';\n        });\n\n    expect(f('hello!!')).toBe('ends with !!');\n    expect(f('nope')).toBe('something else');\n  });\n\n  it(`P.string.minLength(..)`, () => {\n    const f = (input: string | number) =>\n      match(input)\n        .with(P.string.minLength(2), (value) => {\n          type t = Expect<Equal<typeof value, string>>;\n          return 'yes';\n        })\n        .otherwise((value) => {\n          type t = Expect<Equal<typeof value, string | number>>;\n          return 'no';\n        });\n\n    expect(f('aa')).toBe('yes');\n    expect(f('aaa')).toBe('yes');\n    expect(f('a')).toBe('no');\n  });\n\n  it(`P.string.length(..)`, () => {\n    const f = (input: string | number) =>\n      match(input)\n        .with(P.string.length(2), (value) => {\n          type t = Expect<Equal<typeof value, string>>;\n          return 'yes';\n        })\n        .otherwise((value) => {\n          type t = Expect<Equal<typeof value, string | number>>;\n          return 'no';\n        });\n\n    expect(f('aa')).toBe('yes');\n    expect(f('bb')).toBe('yes');\n    expect(f('aaa')).toBe('no');\n    expect(f('a')).toBe('no');\n\n    const f2 = (input: string | number) =>\n      match(input)\n        .with(P.string.length(2), (value) => {\n          type t = Expect<Equal<typeof value, string>>;\n          return 'yes';\n        })\n        // @ts-expect-error matching on specific length isn't exhaustive.\n        .exhaustive();\n  });\n\n  it(`P.string.maxLength(..)`, () => {\n    const f = (input: string | number) =>\n      match(input)\n        .with(P.string.maxLength(10), (value) => {\n          type t = Expect<Equal<typeof value, string>>;\n          return 'yes';\n        })\n        .otherwise((value) => {\n          type t = Expect<Equal<typeof value, string | number>>;\n          return 'no';\n        });\n\n    expect(f('aaa')).toBe('yes');\n    expect(f('aaaaaaaaaa')).toBe('yes');\n    expect(f('aaaaaaaaaaa')).toBe('no');\n  });\n\n  it(`P.string.regex('^[a-z]+$')`, () => {\n    const f = (input: string | number) =>\n      match(input)\n        .with(P.string.regex('^[a-z]+$'), (value) => {\n          type t = Expect<Equal<typeof value, string>>;\n          return 'single word';\n        })\n        .otherwise((value) => {\n          type t = Expect<Equal<typeof value, string | number>>;\n          return 'something else';\n        });\n\n    expect(f('hello')).toBe('single word');\n    expect(f('a b c')).toBe('something else');\n  });\n\n  it(`P.string.regex(/[a-z]+/)`, () => {\n    const f = (input: string | number) =>\n      match(input)\n        .with(P.string.regex(/^https?:\\/\\//), (value) => {\n          type t = Expect<Equal<typeof value, string>>;\n          return 'url';\n        })\n        .otherwise((value) => {\n          type t = Expect<Equal<typeof value, string | number>>;\n          return 'something else';\n        });\n\n    expect(f('https://type-level-typescript.com')).toBe('url');\n    expect(f('a b c')).toBe('something else');\n  });\n});\n"
  },
  {
    "path": "tests/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"strict\": true,\n    \"downlevelIteration\": true,\n    \"noEmit\": true,\n    \"target\": \"ESNext\",\n    \"moduleResolution\": \"node\",\n    \"skipLibCheck\": true,\n    \"esModuleInterop\": true\n  },\n  \"include\": [\".\"],\n  \"exclude\": [\"../src\", \"../dist\", \"../example\", \"../node_modules\"]\n}\n"
  },
  {
    "path": "tests/tuples.test.ts",
    "content": "import { Expect, Equal } from '../src/types/helpers';\nimport { match, P } from '../src';\nimport { State, Event } from './types-catalog/utils';\n\ndescribe('tuple ([a, b])', () => {\n  it('should match tuple patterns', () => {\n    const sum = (xs: number[]): number =>\n      match(xs)\n        .with([], () => 0)\n        .with([P.number, P.number], ([x, y]) => x + y)\n        .with([P.number, P.number, P.number], ([x, y, z]) => x + y + z)\n        .with(\n          [P.number, P.number, P.number, P.number],\n          ([x, y, z, w]) => x + y + z + w\n        )\n        .run();\n\n    expect(sum([2, 3, 2, 4])).toEqual(11);\n  });\n\n  it('should discriminate correctly union of tuples', () => {\n    type Input =\n      | ['+', number, number]\n      | ['*', number, number]\n      | ['-', number]\n      | ['++', number];\n\n    const res = match<Input, number>(['-', 2])\n      .with(['+', P.number, P.number], (value) => {\n        type t = Expect<Equal<typeof value, ['+', number, number]>>;\n        const [, x, y] = value;\n        return x + y;\n      })\n      .with(['*', P.number, P.number], (value) => {\n        type t = Expect<Equal<typeof value, ['*', number, number]>>;\n        const [, x, y] = value;\n        return x * y;\n      })\n      .with(['-', P.number], (value) => {\n        type t = Expect<Equal<typeof value, ['-', number]>>;\n        const [, x] = value;\n        return -x;\n      })\n      .with(['++', P.number], ([, x]) => x + 1)\n      .exhaustive();\n\n    const res2 = match<Input, number>(['-', 2])\n      .with(['+', P._, P._], (value) => {\n        type t = Expect<Equal<typeof value, ['+', number, number]>>;\n        const [, x, y] = value;\n        return x + y;\n      })\n      .with(['*', P._, P._], (value) => {\n        type t = Expect<Equal<typeof value, ['*', number, number]>>;\n        const [, x, y] = value;\n        return x * y;\n      })\n      .with(['-', P._], (value) => {\n        type t = Expect<Equal<typeof value, ['-', number]>>;\n        const [, x] = value;\n        return -x;\n      })\n      .run();\n\n    expect(res).toEqual(-2);\n    expect(res2).toEqual(-2);\n  });\n\n  describe('should match heterogenous tuple patterns', () => {\n    const tuples: { tuple: [string, number]; expected: string }[] = [\n      { tuple: ['coucou', 20], expected: 'number match' },\n      { tuple: ['hello', 20], expected: 'perfect match' },\n      { tuple: ['hello', 21], expected: 'string match' },\n      { tuple: ['azeaze', 17], expected: 'not matching' },\n    ];\n\n    tuples.forEach(({ tuple, expected }) => {\n      it(`should work with ${tuple}`, () => {\n        expect(\n          match<[string, number], string>(tuple)\n            .with(['hello', 20], (x) => {\n              type t = Expect<Equal<typeof x, ['hello', 20]>>;\n              return `perfect match`;\n            })\n            .with(['hello', P._], (x) => {\n              type t = Expect<Equal<typeof x, ['hello', number]>>;\n              return `string match`;\n            })\n            .with([P._, 20], (x) => {\n              type t = Expect<Equal<typeof x, [string, 20]>>;\n              return `number match`;\n            })\n            .with([P.string, P.number], (x) => {\n              type t = Expect<Equal<typeof x, [string, number]>>;\n              return `not matching`;\n            })\n            .exhaustive()\n        ).toEqual(expected);\n      });\n    });\n  });\n\n  it('should work with tuple of records', () => {\n    const initState: State = {\n      status: 'idle',\n    };\n\n    const reducer = (state: State, event: Event): State =>\n      match<[State, Event], State>([state, event])\n        .with([P.any, { type: 'fetch' }], (x) => {\n          type t = Expect<Equal<typeof x, [State, { type: 'fetch' }]>>;\n\n          return {\n            status: 'loading',\n          };\n        })\n\n        .with([{ status: 'loading' }, { type: 'success' }], (x) => {\n          type t = Expect<\n            Equal<\n              typeof x,\n              [\n                { status: 'loading' },\n                { type: 'success'; data: string; requestTime?: number }\n              ]\n            >\n          >;\n\n          return {\n            status: 'success',\n            data: x[1].data,\n          };\n        })\n\n        .with([{ status: 'loading' }, { type: 'error' }], (x) => {\n          type t = Expect<\n            Equal<\n              typeof x,\n              [{ status: 'loading' }, { type: 'error'; error: Error }]\n            >\n          >;\n\n          return {\n            status: 'error',\n            error: x[1].error,\n          };\n        })\n\n        .with([{ status: 'loading' }, { type: 'cancel' }], (x) => {\n          type t = Expect<\n            Equal<typeof x, [{ status: 'loading' }, { type: 'cancel' }]>\n          >;\n\n          return initState;\n        })\n\n        .otherwise(() => state);\n\n    expect(reducer(initState, { type: 'fetch' })).toEqual({\n      status: 'loading',\n    });\n\n    expect(\n      reducer({ status: 'loading' }, { type: 'success', data: 'yo' })\n    ).toEqual({\n      status: 'success',\n      data: 'yo',\n    });\n\n    expect(reducer({ status: 'loading' }, { type: 'cancel' })).toEqual({\n      status: 'idle',\n    });\n  });\n\n  it('should work with as const', () => {\n    type State = { type: 'a' } | { type: 'b' };\n    type Event = { type: 'c' } | { type: 'd' };\n    const state = { type: 'a' } as State;\n    const event = { type: 'c' } as Event;\n\n    const output = match([state, event])\n      .with([{ type: 'a' }, { type: 'c' }], () => 'a + c')\n      .otherwise(() => 'no');\n\n    expect(output).toEqual('a + c');\n  });\n\n  it('should work with nested tuples', () => {\n    type State = {};\n    type Msg = [type: 'Login'] | [type: 'UrlChange', url: string];\n\n    function update(state: State, msg: Msg) {\n      return match<[State, Msg], string>([state, msg])\n        .with([P.any, ['Login']], () => 'ok')\n        .with([P.any, ['UrlChange', P.select()]], () => 'not ok')\n        .exhaustive();\n    }\n  });\n});\n"
  },
  {
    "path": "tests/type-error.test.ts",
    "content": "import { match, P } from '../src';\nimport { Equal, Expect } from '../src/types/helpers';\nimport { Option } from './types-catalog/utils';\n\ntype Country = 'France' | 'Germany' | 'Spain' | 'USA';\n\ndescribe('type errors', () => {\n  it(\"if the inferred pattern type is any, it shouldn't say that the type instanciation is too deep.\", () => {\n    const f = (n: number) => {\n      return (\n        match(n)\n          .with(P.array(P.number), (s) => {\n            return 'big number';\n          })\n          // @ts-expect-error: this isn't a list\n          .exhaustive()\n      );\n    };\n\n    match<Country>('France')\n      // @ts-expect-error: 'Spai' instead of 'Spain'\n      .with('France', 'Germany', 'Spai', (x) => 'Europe')\n      // @ts-expect-error\n      .exhaustive();\n\n    match<Country>('Germany')\n      .with('Germany', 'Spain', () => 'Europe')\n      // @ts-expect-error: 'US' instead of 'USA'\n      .with('US', (x) => 'America')\n      // @ts-expect-error\n      .exhaustive();\n  });\n\n  it(\"If the pattern's wrong, the inferred selection must be the input type\", () => {\n    match<Country>('Germany')\n      .with('Germany', 'Spain', () => 'Europe')\n      // @ts-expect-error: 'US' instead of 'USA'\n      .with('US', (x) => {\n        type t = Expect<Equal<typeof x, 'France' | 'USA'>>;\n        return 'America';\n      })\n      // @ts-expect-error\n      .exhaustive();\n  });\n\n  it(\"Patterns shouldn't accept values which will never match\", () => {\n    const f1 = (input: Option<{ x: number }>) =>\n      match<Option<{ x: number }>>(input)\n        .with({ kind: 'some', value: { x: 2 } }, () => '2')\n        // @ts-expect-error, value.x should be a number\n        .with({ value: { x: '' } }, () => '2')\n        .with({ kind: 'none' }, () => '')\n        .with({ kind: 'some' }, () => '')\n        .exhaustive();\n\n    const f2 = (input: Option<number>) =>\n      match(input)\n        // @ts-expect-error: value is a number\n        .with({ kind: 'some', value: 'string' }, () => '')\n        .with({ kind: 'none' }, () => '')\n        .with({ kind: 'some' }, () => '')\n        .exhaustive();\n  });\n\n  it(\"shouldn't allow when guards with an invalid input\", () => {\n    const startsWith = (start: string) => (value: string) =>\n      value.startsWith(start);\n\n    const equals =\n      <T>(n: T) =>\n      (n2: T) =>\n        n === n2;\n\n    const f = (optionalNumber: Option<number>) =>\n      match(optionalNumber)\n        .with(\n          {\n            kind: 'some',\n            // @ts-expect-error: string isn't assigable to number\n            value: P.when(startsWith('hello')),\n          },\n          () => 'fizz'\n        )\n        .with(\n          {\n            kind: 'some',\n            // @ts-expect-error: string isn't assigable to number\n            value: P.when((x: string) => x),\n          },\n          () => 'fizz'\n        )\n        .with(\n          {\n            kind: 'some',\n            value: P.when((x: number) => x),\n          },\n          () => 'fizz'\n        )\n        .with(\n          {\n            kind: 'some',\n            value: P.when(equals(2)),\n          },\n          () => 'fizz'\n        )\n        .with(\n          {\n            kind: 'some',\n            // @ts-expect-error: string isn't assigable to number\n            value: P.when(equals('yo')),\n          },\n          () => 'fizz'\n        )\n        .with({ kind: 'none' }, () => 'nope')\n        // @ts-expect-error\n        .exhaustive();\n  });\n\n  it(\"if a pattern is any, the outer expression shouldn't throw a type error\", () => {\n    const anyVar = null as any;\n\n    const input = { a: 'a' };\n\n    match(input)\n      .with({ a: anyVar }, (x) => {\n        type t = Expect<Equal<typeof x, typeof input>>;\n        return 'Ok';\n      })\n      .otherwise(() => 'ko');\n  });\n\n  it('type errors should be well placed', () => {\n    match<{\n      a: 1;\n      b: 'hello' | 'bonjour';\n      c: { d: [number, number, boolean] };\n      e: unknown;\n    } | null>(null)\n      .with(\n        {\n          // @ts-expect-error\n          b: 'oops',\n        },\n        () => 'result'\n      )\n      .with(\n        {\n          c: {\n            d: [\n              1, 2,\n              // @ts-expect-error: number instead of boolean\n              3,\n            ],\n          },\n        },\n        () => 'x'\n      )\n      .with({ e: 1 }, () => 'bas')\n      .with({ b: 'hello' }, ({ a }) => 'result')\n      .with({ b: 'bonjour' }, ({ a }) => 'result')\n      .with(null, () => 'result')\n      .exhaustive();\n  });\n});\n"
  },
  {
    "path": "tests/type-is-matching.test.ts",
    "content": "import { Equal, Expect, IsPlainObject, Primitives } from '../src/types/helpers';\nimport { IsMatching } from '../src/types/IsMatching';\nimport { Option } from './types-catalog/utils';\n\ndescribe('IsMatching', () => {\n  describe('should return true if the pattern matches the input,  false otherwise', () => {\n    it('Literals', () => {\n      type cases = [\n        Expect<Equal<IsMatching<'c' | 'd', 'c'>, true>>,\n        Expect<Equal<IsMatching<'c' | 'd', 'a'>, false>>,\n        Expect<Equal<IsMatching<'c' | 'd', unknown>, true>>,\n\n        Expect<Equal<IsMatching<1 | 2, 1>, true>>,\n        Expect<Equal<IsMatching<1 | 2, 3>, false>>,\n        Expect<Equal<IsMatching<1 | 2, unknown>, true>>,\n\n        Expect<Equal<IsMatching<1 | 'a', 1>, true>>,\n        Expect<Equal<IsMatching<1 | 'a', 'a'>, true>>,\n        Expect<Equal<IsMatching<1 | 'a', 2>, false>>,\n        Expect<Equal<IsMatching<1 | 'a', 'b'>, false>>,\n        Expect<Equal<IsMatching<1 | 'a', unknown>, true>>\n      ];\n    });\n\n    describe('Primitives', () => {\n      it('if there is an overlap in either direction, it should match', () => {\n        type res1 = IsMatching<3, number>;\n        type test1 = Expect<Equal<res1, true>>;\n\n        type res2 = IsMatching<number, 3>;\n        type test2 = Expect<Equal<res2, true>>;\n\n        type res3 = IsMatching<'hello', string>;\n        type test3 = Expect<Equal<res3, true>>;\n\n        type res4 = IsMatching<string, 'hello'>;\n        type test4 = Expect<Equal<res4, true>>;\n      });\n\n      it('if there is NO overlap, it should not match', () => {\n        type res1 = IsMatching<3, string>;\n        type test1 = Expect<Equal<res1, false>>;\n\n        type res3 = IsMatching<'hello', number>;\n        type test3 = Expect<Equal<res3, false>>;\n      });\n\n      it('should support unions of primitives', () => {\n        type res1 = IsMatching<string | number, string>;\n        type test1 = Expect<Equal<res1, true>>;\n\n        type res2 = IsMatching<string | number, boolean>;\n        type test2 = Expect<Equal<res2, false>>;\n\n        type res3 = IsMatching<string | number, unknown>;\n        type test3 = Expect<Equal<res3, true>>;\n\n        // if there is an overlap, it matches\n        type res4 = IsMatching<string, number | string>;\n        type test4 = Expect<Equal<res4, true>>;\n      });\n    });\n\n    it('Object', () => {\n      type cases = [\n        Expect<Equal<IsMatching<{}, {}>, true>>,\n        Expect<\n          Equal<\n            IsMatching<{ type: 'a'; color: 'yellow' | 'green' }, { type: 'a' }>,\n            true\n          >\n        >,\n        Expect<\n          Equal<\n            IsMatching<{ type: 'a'; color: 'yellow' | 'green' }, { type: 'b' }>,\n            false\n          >\n        >,\n        Expect<\n          Equal<\n            IsMatching<\n              { type: 'a'; value: { type: 'c'; value: { type: 'd' } } } | 12,\n              { type: 'a' }\n            >,\n            true\n          >\n        >,\n        Expect<\n          Equal<\n            IsMatching<\n              { type: 'a'; value: { type: 'c'; value: { type: 'd' } } } | 12,\n              12\n            >,\n            true\n          >\n        >,\n        Expect<\n          Equal<\n            IsMatching<\n              | {\n                  type: 'a';\n                  value:\n                    | { type: 'c'; value: { type: 'd' } | 2 }\n                    | { type: 'e'; value: { type: 'f' } | 3 };\n                }\n              | 12,\n              { type: 'a'; value: { type: 'c' } }\n            >,\n            true\n          >\n        >,\n        Expect<\n          Equal<\n            IsMatching<\n              | {\n                  type: 'a';\n                  value:\n                    | { type: 'c'; value: { type: 'd' } | 2 }\n                    | { type: 'e'; value: { type: 'f' } | 3 };\n                }\n              | 12,\n              { type: 'a'; value: { type: 'c'; value: 2 } }\n            >,\n            true\n          >\n        >,\n        Expect<\n          Equal<\n            IsMatching<\n              {\n                type: 'a';\n                value:\n                  | { type: 'c'; value: { type: 'd' } | 2 }\n                  | { type: 'e'; value: { type: 'f' } | 3 };\n              },\n              { type: 'a'; value: { type: 'c'; value: 3 } }\n            >,\n            false //  value: 3 isn't compatible with type: 'c'\n          >\n        >,\n        Expect<\n          Equal<\n            IsMatching<12, { type: 'a'; value: { type: 'c'; value: 3 } }>,\n            false\n          >\n        >,\n        Expect<\n          Equal<\n            IsMatching<\n              | { type: 'c'; value: { type: 'd' } | 2 }\n              | { type: 'e'; value: { type: 'f' } | 3 },\n              { type: 'c'; value: 3 }\n            >,\n            false\n          >\n        >,\n        Expect<\n          Equal<\n            IsMatching<\n              | { type: 'c'; value: { type: 'd' } | 2 }\n              | { type: 'e'; value: { type: 'f' } | 3 },\n              { type: 'c' }\n            >,\n            true\n          >\n        >,\n        Expect<\n          Equal<\n            IsMatching<\n              | { type: 'c'; value: { type: 'd' } | 2 }\n              | { type: 'e'; value: { type: 'f' } | 3 },\n              { value: 3 }\n            >,\n            true\n          >\n        >,\n        Expect<\n          Equal<\n            IsMatching<\n              { type: 'c'; value: { type: 'd' } | 2 },\n              { type: 'c'; value: 3 }\n            >,\n            false\n          >\n        >,\n        Expect<\n          Equal<\n            IsMatching<\n              Option<{ type: 'a' } | { type: 'b' }>,\n              { kind: 'some'; value: { type: 'a' } }\n            >,\n            true\n          >\n        >,\n        Expect<\n          Equal<\n            IsMatching<\n              Option<{ type: 'a' } | { type: 'b' }>,\n              { kind: 'some'; value: { type: 'c' } }\n            >,\n            false\n          >\n        >,\n        // the empty object matches everything except null | undefined\n        // just like the `{}` type.\n        Expect<Equal<IsMatching<{ type: 'a' }, {}>, true>>,\n        Expect<Equal<IsMatching<{}, { type: 'a' }>, false>>\n      ];\n    });\n\n    it('Tuples', () => {\n      type State = {};\n      type Msg = [type: 'Login'] | [type: 'UrlChange', url: string];\n\n      type res1 = IsMatching<[State, Msg], [unknown, ['Login', unknown]]>;\n      type test1 = Expect<Equal<res1, false>>;\n\n      type res2 = IsMatching<['a'], []>;\n      type test2 = Expect<Equal<res2, false>>;\n\n      type cases = [\n        Expect<Equal<IsMatching<['a', 'c' | 'd'], ['a', 'd']>, true>>,\n        Expect<Equal<IsMatching<['a', 'c' | 'd'], ['a', unknown]>, true>>,\n        Expect<Equal<IsMatching<['a', 'c' | 'd'], ['a', 'f']>, false>>,\n        Expect<Equal<IsMatching<['a', 'c' | 'd'], ['b', 'c']>, false>>,\n        Expect<Equal<IsMatching<['a', 'c' | 'd', 'd'], ['b', 'c']>, false>>,\n        Expect<Equal<IsMatching<[], []>, true>>,\n        Expect<Equal<IsMatching<['a'], ['a', 'b', 'c']>, false>>,\n        Expect<Equal<IsMatching<[], ['a', 'b', 'c']>, false>>,\n        Expect<\n          Equal<\n            IsMatching<\n              [Option<{ type: 'a' } | { type: 'b' }>, 'c' | 'd'],\n              [{ kind: 'some'; value: { type: 'a' } }, unknown]\n            >,\n            true\n          >\n        >,\n        Expect<\n          Equal<\n            IsMatching<[State, Msg], [unknown, ['UrlChange', unknown]]>,\n            true\n          >\n        >,\n        Expect<Equal<IsMatching<[State, Msg], [unknown, ['Login']]>, true>>\n      ];\n    });\n\n    it('Lists', () => {\n      type cases = [\n        Expect<Equal<IsMatching<('a' | 'b')[], 'a'[]>, true>>,\n        Expect<Equal<IsMatching<('a' | 'b')[], 'b'[]>, true>>,\n        Expect<Equal<IsMatching<('a' | 'b')[], 'c'[]>, false>>,\n        Expect<Equal<IsMatching<{ x: ['a' | 'b'] }[], { x: ['a'] }[]>, true>>,\n        Expect<Equal<IsMatching<{ x: ['a' | 'b'] }[], { x: ['c'] }[]>, false>>\n      ];\n    });\n\n    it('Variadics', () => {\n      type res1 = IsMatching<('a' | 'b')[], [unknown, ...unknown[]]>;\n      type test1 = Expect<Equal<res1, true>>;\n\n      type res2 = IsMatching<[number], [unknown, ...unknown[]]>;\n      type test2 = Expect<Equal<res2, true>>;\n\n      type res3 = IsMatching<[number, number], [unknown, ...unknown[]]>;\n      type test3 = Expect<Equal<res3, true>>;\n\n      type res4 = IsMatching<[], [unknown, ...unknown[]]>;\n      type test4 = Expect<Equal<res4, false>>;\n\n      type res5 = IsMatching<[], [...unknown[], unknown]>;\n      type test5 = Expect<Equal<res5, false>>;\n\n      type res6 = IsMatching<[1, 2], [...unknown[], unknown]>;\n      type test6 = Expect<Equal<res6, true>>;\n\n      type res7 = IsMatching<[1, 2], [1, ...unknown[], 2]>;\n      type test7 = Expect<Equal<res7, true>>;\n\n      type res8 = IsMatching<[1, 3, 2], [1, ...unknown[], 2]>;\n      type test8 = Expect<Equal<res8, true>>;\n\n      type res9 = IsMatching<[1, 3, 2], [1, ...string[], 2]>;\n      type test9 = Expect<Equal<res9, false>>;\n\n      type res10 = IsMatching<[1, 3, 2], [1, ...number[], 2]>;\n      type test10 = Expect<Equal<res10, true>>;\n    });\n\n    it('Sets', () => {\n      type cases = [\n        Expect<Equal<IsMatching<Set<'a' | 'b'>, Set<'a'>>, true>>,\n        Expect<Equal<IsMatching<Set<'a' | 'b'>, Set<'b'>>, true>>,\n        Expect<Equal<IsMatching<Set<'a' | 'b'>, Set<'c'>>, false>>,\n        Expect<\n          Equal<IsMatching<Set<{ x: ['a' | 'b'] }>, Set<{ x: ['a'] }>>, true>\n        >,\n        Expect<\n          Equal<IsMatching<Set<{ x: ['a' | 'b'] }>, Set<{ x: ['c'] }>>, false>\n        >\n      ];\n    });\n\n    it('Maps', () => {\n      type cases = [\n        Expect<\n          Equal<IsMatching<Map<string, 'a' | 'b'>, Map<string, 'a'>>, true>\n        >,\n        Expect<\n          Equal<IsMatching<Map<'hello', 'a' | 'b'>, Map<'hello', 'b'>>, true>\n        >,\n        Expect<\n          Equal<IsMatching<Map<string, 'a' | 'b'>, Map<string, 'c'>>, false>\n        >,\n        Expect<\n          Equal<IsMatching<Map<'hello', 'a' | 'b'>, Map<string, 'a'>>, false>\n        >,\n        Expect<\n          Equal<\n            IsMatching<\n              Map<string, { x: ['a' | 'b'] }>,\n              Map<string, { x: ['a'] }>\n            >,\n            true\n          >\n        >,\n        Expect<\n          Equal<\n            IsMatching<\n              Map<string, { x: ['a' | 'b'] }>,\n              Map<string, { x: ['c'] }>\n            >,\n            false\n          >\n        >\n      ];\n    });\n\n    it('pattern is a union types', () => {\n      type cases = [\n        Expect<Equal<IsMatching<'d', 'd' | 'e'>, true>>,\n        Expect<Equal<IsMatching<'f', 'd' | 'e'>, false>>,\n        Expect<\n          Equal<\n            IsMatching<\n              | { type: 'd'; value: boolean }\n              | { type: 'e'; value: string[] }\n              | { type: 'f'; value: number[] },\n              {\n                type: 'd' | 'e';\n              }\n            >,\n            true\n          >\n        >\n      ];\n    });\n  });\n});\n"
  },
  {
    "path": "tests/types-catalog/definition.ts",
    "content": "interface RequestStyle {\n  palette?: string;\n}\n\ntype AxisBound = string | number;\ntype Aggregator = 'sum' | 'avg';\n\ninterface Axis {\n  label?: string;\n  scale?: 'linear' | 'log';\n  min?: AxisBound;\n  max?: AxisBound;\n  include_zero?: boolean;\n  units?: boolean;\n}\n\ninterface DistributionXAxis {\n  scale?: 'linear' | 'log';\n  min?: AxisBound;\n  max?: AxisBound;\n  include_zero?: boolean;\n}\n\ninterface DistributionYAxis {\n  label?: string;\n  scale?: 'linear' | 'log';\n  min?: AxisBound;\n  max?: AxisBound;\n  include_zero?: boolean;\n  units?: boolean;\n}\n\ninterface Marker {\n  value?: string;\n  time?: string;\n  display_type?: string;\n  label?: string;\n  val?: number;\n  min?: number;\n  max?: number;\n  type?: string;\n  from_ts?: string;\n  to_ts?: string;\n  ts?: string;\n  on_right_yaxis?: boolean;\n  is_hovered?: boolean;\n}\n\ninterface Event {\n  q: string;\n  tags_execution?: 'TagsExecution';\n}\n\ntype Markers = Marker[];\n\ninterface ConditionalFormat {\n  comparator: 'Comparator';\n  value?: number | string;\n  palette: string;\n  custom_bg_color?: string;\n  custom_fg_color?: string;\n  image_url?: string;\n  hide_value?: boolean;\n  metric?: string;\n}\n\ninterface ContextMenuLink {\n  link?: string;\n  is_hidden?: boolean;\n}\n\ninterface UserDefinedLink {\n  label: string;\n  link: string;\n}\n\ntype CustomLink = ContextMenuLink | UserDefinedLink;\n\ntype OrderDir = 'a' | 'b';\n\ntype EventCompute = {\n  aggregation: string;\n  interval?: number;\n  facet?: string;\n};\n\ninterface GroupBy {\n  facet: string;\n  limit?: number;\n  sort?: {\n    aggregation: string;\n    order: OrderDir;\n    facet?: string;\n  };\n  should_exclude_missing?: boolean;\n}\n\ntype EventQuery = {\n  index?: string;\n  compute?: EventCompute;\n  multi_compute?: EventCompute[];\n  search?: {\n    query: string;\n  };\n  group_by?: GroupBy[];\n};\n\ntype MetricQuery = string;\n\ntype ProcessQuery = {\n  metric: string;\n  search_by?: string;\n  filter_by?: string[];\n  query_filter?: string;\n  limit: number;\n  is_normalized_cpu?: boolean;\n};\n\ninterface QueryTableColumnRequest {\n  name: string;\n  alias?: string;\n  order?: OrderDir;\n}\n\ninterface ApmStatsQuery {\n  service: string;\n  env: string;\n  name: string;\n  resource?: string;\n  columns?: QueryTableColumnRequest[];\n}\n\ninterface MetricRequest {\n  metrics_query: MetricQuery;\n  preTemplateQuery?: string;\n  _query_options?: object;\n}\ninterface LogRequest {\n  logs_query: EventQuery;\n}\ninterface ApmRequest {\n  apm_query: EventQuery;\n}\ninterface ApmStatsRequest {\n  apm_stats_query: ApmStatsQuery;\n}\ninterface RumRequest {\n  rum_query: EventQuery;\n}\ninterface EventRequest {\n  events_query: EventQuery;\n}\ninterface ProcessRequest {\n  process_query: ProcessQuery;\n}\n\ninterface ComplianceFindingsRequest {\n  compliance_findings_query: EventQuery;\n}\n\ninterface IssuesRequest {\n  issues_query_query: EventQuery;\n}\ninterface AuditRequest {\n  audit_query: EventQuery;\n}\n\ntype FormulaEventsDataSource =\n  | 'logs'\n  | 'spans'\n  | 'rum'\n  | 'network'\n  | 'security_signals'\n  | 'profiles'\n  | 'events'\n  | 'ci_pipelines'\n  | 'ci_tests'\n  | 'compliance_findings'\n  | 'database_queries'\n  | 'synthetics_batches'\n  | 'app_sec_events'\n  | 'app_sec_spans'\n  | 'audit';\n\ntype FormulaMetricsQuery = {\n  name: string;\n  data_source: 'metrics' | 'cloud_cost';\n  query: string;\n  aggregator?: Aggregator;\n};\n\ntype EventsCompute = {\n  aggregation: EventsAggregator;\n  metric?: string;\n  interval?: number;\n};\n\ntype EventsAggregator =\n  | 'count'\n  | 'cardinality'\n  | 'median'\n  | 'pc75'\n  | 'pc90'\n  | 'pc95'\n  | 'pc98'\n  | 'pc99'\n  | 'sum'\n  | 'min'\n  | 'max'\n  | 'avg';\n\ntype EventsGroupBy = {\n  facet: string;\n  limit?: number;\n  sort?: {\n    aggregation: EventsAggregator;\n    order?: OrderDir;\n    metric?: string;\n  };\n  should_exclude_missing?: boolean;\n};\n\ntype FormulaEventsQuery = {\n  name: string;\n  data_source: FormulaEventsDataSource;\n  compute: EventsCompute;\n  search?: {\n    query: string;\n  };\n  indexes?: string[];\n  group_by?: EventsGroupBy[];\n};\n\ntype FormulaProcessQuery = {\n  name: string;\n  data_source: 'process' | 'container';\n  metric: string;\n  text_filter?: string;\n  tag_filters?: string[];\n  query_filter?: string;\n  limit?: number;\n  sort?: OrderDir;\n  is_normalized_cpu?: boolean;\n  aggregator?: Aggregator;\n};\n\ninterface FormulaApmDependencyStatsQuery {\n  name: string;\n  data_source: 'apm_dependency_stats';\n  env: string;\n  is_upstream?: boolean;\n  operation_name: string;\n  primary_tag_name?: string;\n  primary_tag_value?: string;\n  resource_name: string;\n  service: string;\n}\n\ninterface FormulaApmResourceStatsQuery {\n  name: string;\n  data_source: 'apm_resource_stats';\n  env: string;\n  group_by?: string[];\n  operation_name: string;\n  primary_tag_name?: string;\n  primary_tag_value?: string;\n  resource_name?: string;\n  service: string;\n}\n\ntype FormulaApmStatsQuery =\n  | FormulaApmDependencyStatsQuery\n  | FormulaApmResourceStatsQuery;\n\ntype FormulaIncidentsQuery = {\n  name: string;\n  data_source: 'incident_analytics';\n  compute: EventsCompute;\n  search?: {\n    query: string;\n  };\n  indexes?: string[];\n  group_by?: EventsGroupBy[];\n};\n\ntype FormulaQuery =\n  | FormulaMetricsQuery\n  | FormulaEventsQuery\n  | FormulaProcessQuery\n  | FormulaApmStatsQuery\n  | FormulaIncidentsQuery;\n\ntype FormulaQueries = FormulaQuery[];\n\ntype Formula = {\n  formula: string;\n  alias?: string;\n  limit?: {\n    count?: number;\n    order?: OrderDir;\n  };\n};\n\ninterface TimeseriesFormulaRequest extends TimeseriesRequest {\n  response_format: 'timeseries';\n  formulas?: Formula[];\n  queries: FormulaQueries;\n}\n\ntype ScalarFormulaRequest = {\n  response_format: 'scalar';\n  formulas?: Formula[];\n  queries: FormulaQueries;\n};\n\ntype SQLTimeseriesRequest = {\n  request_type: 'sql';\n  response_format: 'timeseries';\n  sql_query: string;\n};\n\ntype SQLTableRequest = {\n  request_type: 'sql';\n  response_format: 'scalar';\n  sql_query: string;\n};\n\ntype EventPlatformRequest =\n  | LogRequest\n  | ApmRequest\n  | RumRequest\n  | ComplianceFindingsRequest\n  | EventRequest\n  | IssuesRequest\n  | AuditRequest;\n\ntype TimeseriesDataSourceRequest =\n  | MetricRequest\n  | EventRequest\n  | ProcessRequest\n  | EventPlatformRequest\n  | TimeseriesFormulaRequest\n  | SQLTimeseriesRequest;\n\ninterface TimeseriesRequestStyle {\n  palette?: string;\n}\n\ninterface Metadata {\n  [key: string]: { alias: string };\n}\n\ntype DisplayType = 'line' | 'bar' | 'area';\n\ninterface TimeseriesRequest {\n  type?: DisplayType;\n  metadata?: Metadata;\n  style?: TimeseriesRequestStyle;\n  on_right_yaxis?: boolean;\n}\n\ntype TimeseriesDefinitionRequest = TimeseriesDataSourceRequest &\n  TimeseriesRequest;\n\ninterface TimeseriesDefinition {\n  viz: 'timeseries';\n  requests: TimeseriesDefinitionRequest[];\n  yaxis?: Axis;\n  right_yaxis?: Axis;\n  events?: Event[];\n  markers?: Marker[];\n  custom_links?: CustomLink[];\n}\n\ntype TableFormula = Formula & {\n  conditional_formats?: ConditionalFormat[];\n};\n\ntype TableFormulaRequest = {\n  formulas?: TableFormula[];\n  response_format: 'scalar';\n  queries: FormulaQueries;\n};\n\ntype QueryTableDataSourceRequest =\n  | MetricRequest\n  | EventPlatformRequest\n  | ApmStatsRequest\n  | TableFormulaRequest\n  | SQLTableRequest;\n\ninterface QueryTableRequest {\n  aggregator?: Aggregator;\n  limit?: number;\n  order?: OrderDir;\n  alias?: string;\n  conditional_formats?: ConditionalFormat[];\n}\n\ntype QueryTableDefinitionRequest = QueryTableDataSourceRequest &\n  QueryTableRequest;\n\ntype HasSearchBar = 'always' | 'never' | 'auto';\n\ninterface QueryTableDefinition {\n  viz: 'query_table';\n  requests: QueryTableDefinitionRequest[];\n  has_search_bar?: HasSearchBar;\n  custom_links?: CustomLink[];\n}\n\ninterface HeatmapRequest {\n  style?: RequestStyle;\n}\n\ninterface HeatmapDefinitionRequest extends MetricRequest, HeatmapRequest {}\n\ninterface HeatmapDefinition {\n  viz: 'heatmap';\n  requests: HeatmapDefinitionRequest[];\n  yaxis?: Axis;\n  events?: Event[];\n  custom_links?: CustomLink[];\n}\n\ninterface ServiceMapDefinition {\n  viz: 'servicemap';\n  requests?: undefined;\n  custom_links?: CustomLink[];\n}\n\ntype TreemapProcessMemoryRequest = { q: string };\n\ntype TreemapDataSourceRequest =\n  | ScalarFormulaRequest\n  | TreemapProcessMemoryRequest;\n\ntype TreemapSizeBy = 'pct_cpu' | 'pct_mem';\n\ntype TreemapColorBy = 'user';\n\ntype TreemapGroupBy = 'family' | 'process' | 'user';\n\ninterface TreemapDefinition {\n  viz: 'treemap';\n  requests: TreemapDataSourceRequest[];\n  size_by?: TreemapSizeBy;\n  color_by?: TreemapColorBy;\n  group_by?: TreemapGroupBy;\n}\n\ninterface TopListRequest {\n  conditional_formats?: ConditionalFormat[];\n}\n\ntype TopListDataSourceRequest =\n  | MetricRequest\n  | EventPlatformRequest\n  | ProcessRequest\n  | ScalarFormulaRequest\n  | SQLTableRequest;\n\ntype TopListDefinitionRequest = TopListDataSourceRequest & TopListRequest;\n\ninterface TopListDefinition {\n  viz: 'toplist';\n  requests: TopListDefinitionRequest[];\n  custom_links?: CustomLink[];\n}\n\ntype DistributionDataSourceRequest =\n  | MetricRequest\n  | ProcessRequest\n  | ApmStatsRequest\n  | EventPlatformRequest;\n\ninterface DistributionRequest {\n  style?: RequestStyle;\n}\n\ntype DistributionDefinitionRequest = DistributionDataSourceRequest &\n  DistributionRequest;\n\ninterface DistributionDefinition {\n  viz: 'distribution';\n  requests: DistributionDefinitionRequest[];\n  xaxis?: DistributionXAxis;\n  yaxis?: DistributionYAxis;\n  markers?: Markers;\n  custom_links?: CustomLink[];\n}\n\ntype ScatterPlotDimension = 'x' | 'y' | 'radius' | 'color';\n\ntype ScatterplotFormula = Formula & {\n  dimension: ScatterPlotDimension;\n};\n\ninterface ScatterplotScalarFormulaRequest extends ScalarFormulaRequest {\n  formulas: ScatterplotFormula[];\n}\n\ntype ScatterplotDataSourceRequest =\n  | MetricRequest\n  | ScatterplotScalarFormulaRequest\n  | SQLTableRequest;\n\ninterface ScatterplotRequest {\n  aggregator?: Aggregator;\n}\n\ntype ScatterplotDefinitionRequest = ScatterplotDataSourceRequest &\n  ScatterplotRequest;\n\ninterface ScatterplotDefinition {\n  viz: 'scatterplot';\n  requests: ScatterplotDefinitionRequest[];\n  custom_links?: CustomLink[];\n  xaxis?: Axis;\n  yaxis?: Axis;\n  color_by_groups?: string[];\n}\n\ninterface GeomapStyle {\n  palette_flip: boolean;\n}\n\ninterface GeomapView {\n  focus: string;\n}\n\ntype GeomapDefinitionRequest =\n  | MetricRequest\n  | EventPlatformRequest\n  | ScalarFormulaRequest\n  | SQLTableRequest;\n\ninterface GeomapDefinition {\n  viz: 'geomap';\n  requests: GeomapDefinitionRequest[];\n  custom_links?: CustomLink[];\n  style: GeomapStyle;\n  view: GeomapView;\n}\n\ntype PlotPaletteName = 'red' | 'blue' | 'orange';\n\ntype SunburstRequest = {\n  style?: {\n    palette?: PlotPaletteName;\n  };\n};\n\ninterface SunburstDefinitionRequest\n  extends ScalarFormulaRequest,\n    SunburstRequest {}\n\ntype SunburstKnownLegend =\n  | { type: 'table' }\n  | { type: 'inline'; hide_value?: boolean; hide_percent?: boolean }\n  | { type: 'none' };\n\ntype SunburstLegend =\n  | { type: 'automatic'; hide_value?: boolean; hide_percent?: boolean }\n  | SunburstKnownLegend;\n\ntype SunburstDefinition = {\n  viz: 'sunburst';\n  requests: SunburstDefinitionRequest[];\n  hide_total?: boolean;\n  legend?: SunburstLegend;\n};\n\ntype WildcardDefinitionRequest = SQLTableRequest | ScalarFormulaRequest;\n\ntype WildcardDefinition = {\n  viz: 'wildcard';\n  requests: WildcardDefinitionRequest[];\n  specification: {\n    type: 'vega' | 'vega-lite';\n    contents: object;\n  };\n};\n\nexport type Definition =\n  | TimeseriesDefinition\n  | QueryTableDefinition\n  | HeatmapDefinition\n  | ServiceMapDefinition\n  | TreemapDefinition\n  | TopListDefinition\n  | DistributionDefinition\n  | ScatterplotDefinition\n  | GeomapDefinition\n  | SunburstDefinition\n  | WildcardDefinition;\n"
  },
  {
    "path": "tests/types-catalog/utils.ts",
    "content": "export type Option<a> = { kind: 'none' } | { kind: 'some'; value: a };\n\nexport const none: Option<never> = { kind: 'none' };\nexport const some = <a>(value: a): Option<a> => ({\n  kind: 'some',\n  value,\n});\n\nexport type Blog = {\n  id: number;\n  title: string;\n};\n\nexport type State =\n  | { status: 'idle' }\n  | { status: 'loading' }\n  | { status: 'success'; data: string }\n  | { status: 'error'; error: Error };\n\nexport type Event =\n  | { type: 'fetch' }\n  | { type: 'success'; data: string; requestTime?: number }\n  | { type: 'error'; error: Error }\n  | { type: 'cancel' };\n\nexport type BigUnion =\n  | 'a'\n  | 'b'\n  | 'c'\n  | 'd'\n  | 'e'\n  | 'f'\n  | 'g'\n  | 'h'\n  | 'i'\n  | 'j'\n  | 'k'\n  | 'l'\n  | 'm'\n  | 'n'\n  | 'o'\n  | 'p'\n  | 'q'\n  | 'r'\n  | 's'\n  | 't'\n  | 'u'\n  | 'v'\n  | 'w'\n  | 'x'\n  | 'y'\n  | 'z';\n\ntype AsyncResultStatus = 'idle' | 'loading' | 'error' | 'success';\n\nexport interface BaseAsyncResult<TData, TError = Error> {\n  status: AsyncResultStatus;\n  data?: TData;\n  error?: TError;\n}\n\nexport interface AsyncResultIdleOrLoading<TData, TError = Error>\n  extends BaseAsyncResult<TData, TError> {\n  status: 'idle' | 'loading';\n}\n\nexport interface AsyncResultSuccess<TData, TError = Error>\n  extends BaseAsyncResult<TData, TError> {\n  status: 'success';\n  data: TData;\n}\n\nexport interface AsyncResultError<TData, TError = Error>\n  extends BaseAsyncResult<TData, TError> {\n  status: 'error';\n  error: TError;\n}\nexport type AsyncResult<TData, TError = Error> =\n  | AsyncResultIdleOrLoading<TData, TError>\n  | AsyncResultSuccess<TData, TError>\n  | AsyncResultError<TData, TError>;\n"
  },
  {
    "path": "tests/types.test.ts",
    "content": "import { Expect, Equal } from '../src/types/helpers';\nimport { match, P } from '../src';\nimport { State, Event } from './types-catalog/utils';\n\ndescribe('types', () => {\n  type Input = [State, Event];\n\n  it('wildcard patterns should typecheck', () => {\n    let pattern: P.Pattern<Input>;\n    pattern = P._;\n    pattern = [P._, P._];\n    pattern = [{ status: 'success', data: '' }, P._];\n    pattern = [{ status: 'success', data: P.string }, P._];\n    pattern = [{ status: 'success', data: P._ }, P._];\n    pattern = [{ status: 'error', error: P.instanceOf(Error) }, P._];\n    pattern = [{ status: 'idle' }, P._];\n    pattern = [P._, { type: 'fetch' }];\n    pattern = [P._, { type: P._ }];\n    pattern = [{ status: 'idle' }, { type: 'fetch' }];\n    pattern = [{ status: P._ }, { type: P._ }];\n  });\n\n  it('guard patterns should typecheck', () => {\n    const pattern1: P.Pattern<Input> = P.when(() => true);\n    const pattern2: P.Pattern<Input> = P.when((x) => {\n      type t = Expect<Equal<typeof x, Input>>;\n      return true;\n    });\n\n    const pattern3: P.Pattern<Input> = [\n      P.when((state) => {\n        type t = Expect<Equal<typeof state, State>>;\n        return !!state;\n      }),\n      P.when((event) => {\n        type t = Expect<Equal<typeof event, Event>>;\n        return !!event;\n      }),\n    ];\n\n    const pattern3_1: P.Pattern<Input> = [\n      P._,\n      { type: P.when((t: Event['type']) => true) },\n    ];\n\n    const pattern4: P.Pattern<Input> = [\n      {\n        status: 'success',\n        data: P.when((d) => {\n          type t = Expect<Equal<typeof d, string>>;\n          return true;\n        }),\n      },\n      P._,\n    ];\n\n    const pattern4_1: P.Pattern<Input> = [{ status: 'error', data: '' }, P._];\n\n    const pattern5: P.Pattern<Input> = [\n      P._,\n      { type: P.when((t: Event['type']) => true) },\n    ];\n\n    const isFetch = (type: string): type is 'fetch' => type === 'fetch';\n\n    const pattern6: P.Pattern<Input> = [P._, { type: P.when(isFetch) }];\n\n    const pattern7: P.Pattern<{ x: string }> = {\n      x: P.when((x) => {\n        type t = Expect<Equal<typeof x, string>>;\n        return true;\n      }),\n    };\n\n    const pattern8: P.Pattern<[{ x: string }]> = [\n      {\n        x: P.when((x) => {\n          type t = Expect<Equal<typeof x, string>>;\n          return true;\n        }),\n      },\n    ];\n\n    const pattern9: P.Pattern<[{ x: string }, { y: number }]> = [\n      {\n        x: P.when((x) => {\n          type t = Expect<Equal<typeof x, string>>;\n          return true;\n        }),\n      },\n      {\n        y: P.when((y) => {\n          type t = Expect<Equal<typeof y, number>>;\n          return true;\n        }),\n      },\n    ];\n\n    const pattern10: P.Pattern<string | number> = P.when((x) => {\n      type t = Expect<Equal<typeof x, string | number>>;\n      return true;\n    });\n  });\n\n  it('should infer values correctly in handler', () => {\n    type Input = { type: string; hello?: { yo: number } } | string;\n\n    match<Input>({ type: 'hello' }).with(P.string, (x) => {\n      type t = Expect<Equal<typeof x, string>>;\n      return 'ok';\n    });\n\n    const res = match<Input>({ type: 'hello' }).with(P.string, (x) => {\n      type t = Expect<Equal<typeof x, string>>;\n      return 'ok';\n    });\n\n    match<Input>({ type: 'hello' }).with(\n      P.when((x) => true),\n      (x) => {\n        type t = Expect<Equal<typeof x, Input>>;\n        return 'ok';\n      }\n    );\n\n    match<Input>({ type: 'hello' }).with(\n      P.when((x) => {\n        type t = Expect<Equal<typeof x, Input>>;\n        return true;\n      }),\n      (x) => {\n        type t = Expect<Equal<typeof x, Input>>;\n        return 'ok';\n      }\n    );\n    match<Input>({ type: 'hello' }).with(P.not('hello' as const), (x) => {\n      type t = Expect<Equal<typeof x, Input>>;\n      return 'ok';\n    });\n    match<Input>({ type: 'hello' }).with(P.not(P.string), (x) => {\n      type t = Expect<\n        Equal<\n          typeof x,\n          {\n            type: string;\n            hello?: {\n              yo: number;\n            };\n          }\n        >\n      >;\n      return 'ok';\n    });\n    match<Input>({ type: 'hello' })\n      .with(P.not(P.when((x) => true)), (x) => {\n        type t = Expect<Equal<typeof x, Input>>;\n        return 'ok';\n      })\n      .with({ type: P._ }, (x) => {\n        type t = Expect<\n          Equal<\n            typeof x,\n            {\n              type: string;\n              hello?: {\n                yo: number;\n              };\n            }\n          >\n        >;\n        return 'ok';\n      });\n    match<Input>({ type: 'hello' }).with({ type: P.string }, (x) => {\n      type t = Expect<\n        Equal<typeof x, { type: string; hello?: { yo: number } | undefined }>\n      >;\n      return 'ok';\n    });\n    match<Input>({ type: 'hello' }).with({ type: P.when((x) => true) }, (x) => {\n      type t = Expect<\n        Equal<typeof x, { type: string; hello?: { yo: number } | undefined }>\n      >;\n      return 'ok';\n    });\n    match<Input>({ type: 'hello' }).with(\n      { type: P.not('hello' as 'hello') },\n      (x) => {\n        type t = Expect<\n          Equal<\n            typeof x,\n            {\n              type: string;\n              hello?: { yo: number } | undefined;\n            }\n          >\n        >;\n        return 'ok';\n      }\n    );\n\n    match<Input>({ type: 'hello' }).with({ type: P.not(P.string) }, (x) => {\n      type t = Expect<Equal<typeof x, Input>>;\n      return 'ok';\n    });\n    match<Input>({ type: 'hello' }).with(\n      { type: P.not(P.when((x) => true)) },\n      (x) => {\n        type t = Expect<Equal<typeof x, Input>>;\n        return 'ok';\n      }\n    );\n    match<Input>({ type: 'hello' }).with(\n      P.not({ type: P.when((x) => true) }),\n      (x) => {\n        type t = Expect<Equal<typeof x, string>>;\n        return 'ok';\n      }\n    );\n    match<Input>({ type: 'hello' }).with(P.not({ type: P.string }), (x) => {\n      type t = Expect<Equal<typeof x, string>>;\n      return 'ok';\n    });\n    match<Input>({ type: 'hello' }).with(P._, (x) => {\n      type t = Expect<Equal<typeof x, Input>>;\n      return 'ok';\n    });\n  });\n\n  it('a union of object or primitive should be matched with a correct type inference', () => {\n    type Input =\n      | string\n      | number\n      | boolean\n      | { type: string | number }\n      | string[]\n      | [number, number];\n\n    match<Input>({ type: 'hello' })\n      .with(P.string, (x) => {\n        type t = Expect<Equal<typeof x, string>>;\n        return 'ok';\n      })\n      .with(P.number, (x) => {\n        type t = Expect<Equal<typeof x, number>>;\n        return 'ok';\n      })\n      .with(P.boolean, (x) => {\n        type t = Expect<Equal<typeof x, boolean>>;\n        return 'ok';\n      })\n      .with({ type: P.string }, (x) => {\n        type t = Expect<Equal<typeof x, { type: string }>>;\n        return 'ok';\n      })\n      .with({ type: P._ }, (x) => {\n        type t = Expect<Equal<typeof x, { type: string | number }>>;\n        return 'ok';\n      })\n      .with([P.string], (x) => {\n        type t = Expect<Equal<typeof x, [string]>>;\n        return 'ok';\n      })\n      .with([P.number, P.number], (x) => {\n        type t = Expect<Equal<typeof x, [number, number]>>;\n        return 'ok';\n      })\n      .run();\n  });\n\n  describe('Unknown Input', () => {\n    const users: unknown = [{ name: 'Gabriel', postCount: 20 }];\n\n    const typedUsers = match(users)\n      .with([{ name: P.string, postCount: P.number }], (users) => users)\n      .otherwise(() => []);\n\n    // type of `typedUsers` is { name: string, postCount: number }[]\n\n    expect(\n      typedUsers\n        .map((user) => `<p>${user.name} has ${user.postCount} posts.</p>`)\n        .join('')\n    ).toEqual(`<p>Gabriel has 20 posts.</p>`);\n  });\n\n  it(\"should enforce all branches return the right typeP. when it's set\", () => {\n    match<number, number>(2)\n      //  @ts-expect-error\n      .with(2, () => 'string')\n      //  @ts-expect-error\n      .otherwise(() => '?');\n  });\n\n  it('issue #73: should enforce the handler as the right type', () => {\n    const f = (x: number) => x.toLocaleString();\n    const g = (x: string) => x.toUpperCase();\n    expect(() =>\n      match(false)\n        // @ts-expect-error\n        .with(true, f)\n        // @ts-expect-error\n        .with(false, g)\n        // @ts-expect-error\n        .with(true, (n: string) => '')\n        .exhaustive()\n    ).toThrow();\n  });\n});\n\ndescribe('type narrowing inheritence', () => {\n  describe('on a discriminated union type, once a case is handled it should be excluded from the input type', () => {\n    it('union of literals', () => {\n      const f = (input: 'a' | 'b') =>\n        match(input)\n          .with('a', () => 'a handled')\n          // @ts-expect-error duplicates shouldn't be permitted\n          .with('a', () => 'duplicated')\n          .with('b', () => 'b handled')\n          .exhaustive();\n\n      const f2 = (input: 'a' | 'b' | 2 | 1) =>\n        match(input)\n          .with('a', () => 'a handled')\n          .with('b', () => 'b handled')\n          .with(1, () => '1 handled')\n          // @ts-expect-error duplicates shouldn't be permitted\n          .with(1, () => 'duplicated')\n          .with(2, () => '2 handled')\n          .exhaustive();\n    });\n\n    it('union of objects', () => {\n      type Input = { type: 'a'; data: string } | { type: 'b'; data: number };\n\n      const f = (input: Input) =>\n        match(input)\n          .with({ type: 'a' }, () => 'a handled')\n          .with(\n            {\n              // @ts-expect-error duplicates shouldn't be permitted\n              type: 'a',\n            },\n            () => 'duplicated'\n          )\n          .with({ type: 'b' }, () => 'b handled')\n          .exhaustive();\n    });\n\n    it('should error after P.any', () => {\n      type Input = { type: 'a'; data: string } | { type: 'b'; data: number };\n\n      const f = (input: Input) =>\n        match(input)\n          .with(P.any, () => 'a handled')\n          // @ts-expect-error\n          .with({ type: 'a' }, () => 'duplicated')\n          .exhaustive();\n    });\n\n    it(\"shouldn't exclude in case of primitive type\", () => {\n      const width = 100;\n      const height = 200;\n      const size = 10;\n      let canShowInlineLegend = true as boolean;\n\n      match<boolean>(true)\n        .with(size >= 100 && width > height * 2.25, () => 'table')\n        .with(size >= 100 && height > width * 1.5, () => 'table')\n        .with(canShowInlineLegend, () => 'inline')\n        .otherwise(() => 'none');\n    });\n  });\n\n  it('should correctly instantiate the input type on every pattern creator functions', () => {\n    match<'a' | 'b'>('a').with(\n      P.when((x) => {\n        type test = Expect<Equal<typeof x, 'a' | 'b'>>;\n        return true;\n      }),\n      () => 'a'\n    );\n\n    match<'a' | 'b'>('a').with(\n      // @ts-expect-error\n      P.union('somethingwrong'),\n      () => 'a'\n    );\n\n    match<{ type: 'a' } | { type: 'b' }>({ type: 'a' }).with(\n      // @ts-expect-error\n      P.intersection('asd'),\n      () => 'a'\n    );\n\n    match<{ type: 'a' } | { type: 'b' }>({ type: 'a' }).with(\n      // @ts-expect-error\n      P.intersection('asd'),\n      () => 'a'\n    );\n\n    match<{ type: 'a' } | { type: 'b' }>({ type: 'a' }).with(\n      P.intersection({\n        // @ts-expect-error\n        type: P.union('oops'),\n      }),\n      () => 'a'\n    );\n\n    match<{ type: 'a' } | { type: 'b' }>({ type: 'a' }).with(\n      // @ts-expect-error\n      P.optional('asd'),\n      () => 'a'\n    );\n\n    match<{ type: 'a' } | { type: 'b' }>({ type: 'a' }).with(\n      P.optional({\n        // @ts-expect-error\n        type: P.union('oops'),\n      }),\n      () => 'a'\n    );\n  });\n});\n"
  },
  {
    "path": "tests/unions.test.ts",
    "content": "import { Expect, Equal } from '../src/types/helpers';\nimport { match, P } from '../src';\nimport { Option } from './types-catalog/utils';\n\ndescribe('Unions (a | b)', () => {\n  it('should match discriminated unions', () => {\n    const val: Option<string> = {\n      kind: 'some',\n      value: 'hello',\n    };\n\n    const res = match(val as Option<string>)\n      .with({ kind: 'some' }, (o) => {\n        type t = Expect<Equal<typeof o, { kind: 'some'; value: string }>>;\n        return o.value;\n      })\n      .with({ kind: 'none' }, () => 'no value')\n      .exhaustive();\n\n    type t = Expect<Equal<typeof res, string>>;\n\n    expect(res).toEqual('hello');\n  });\n\n  it('should discriminate union types correctly 2', () => {\n    type Post = {\n      type: 'post';\n      id: number;\n      content: { body: string };\n    };\n    type Video = { type: 'video'; id: number; content: { src: string } };\n    type Image = { type: 'image'; id: number; content: { src: number } };\n\n    type Input = Post | Video | Image;\n\n    const res = match<Input>({\n      type: 'post',\n      id: 2,\n      content: { body: 'yo' },\n    })\n      .with({ type: 'post', id: 7 }, (x) => {\n        type t = Expect<\n          Equal<\n            typeof x,\n            {\n              content: {\n                body: string;\n              };\n              type: 'post';\n              id: 7;\n            }\n          >\n        >;\n        return 1;\n      })\n      .with({ type: 'post', content: P._ }, (x) => {\n        type t = Expect<Equal<typeof x, Post>>;\n        return 1;\n      })\n      .with({ type: 'video', content: { src: P.string } }, (x) => {\n        type t = Expect<Equal<typeof x, Video>>;\n        return 2;\n      })\n      .with({ type: 'image' }, (x) => {\n        type t = Expect<Equal<typeof x, Image>>;\n        return 3;\n      })\n      .exhaustive();\n\n    expect(res).toEqual(1);\n  });\n\n  it('should discriminate union types correctly 3', () => {\n    type Text = { type: 'text'; content: string };\n    type Img = { type: 'img'; src: string };\n    type Video = { type: 'video'; src: string };\n    type Story = {\n      type: 'story';\n      likes: number;\n      views: number;\n      author: string;\n      src: string;\n    };\n    type Data = Text | Img | Video | Story;\n\n    type Ok<T> = { type: 'ok'; data: T };\n    type ResError<T> = { type: 'error'; error: T };\n\n    type Result<TError, TOk> = Ok<TOk> | ResError<TError>;\n\n    const result = {\n      type: 'ok',\n      data: { type: 'img', src: 'hello.com' },\n    } as Result<Error, Data>;\n\n    const ouput = match(result)\n      .with({ type: 'ok', data: { type: 'text' } }, (res) => {\n        type t = Expect<Equal<typeof res, Ok<Text>>>;\n        return `<p>${res.data.content}</p>`;\n      })\n      .with({ type: 'ok', data: { type: 'img' } }, (res) => {\n        type t = Expect<Equal<typeof res, Ok<Img>>>;\n        return `<img src=\"${res.data.src}\" />`;\n      })\n      .with({ type: 'ok', data: { type: 'story', likes: 10 } }, (res) => {\n        type t = Expect<\n          Equal<\n            typeof res,\n            {\n              type: 'ok';\n              data: {\n                author: string;\n                src: string;\n                views: number;\n                type: 'story';\n                likes: 10;\n              };\n            }\n          >\n        >;\n        return `<div>story with ${res.data.likes} likes</div>`;\n      })\n      .with({ type: 'error' }, (res) => {\n        type t = Expect<Equal<typeof res, ResError<Error>>>;\n        return '<p>Oups! An error occured</p>';\n      })\n      .otherwise(() => '<p>everything else</p>');\n\n    expect(ouput).toEqual('<img src=\"hello.com\" />');\n  });\n\n  it('Issue #41 — should be possible to pattern match on error objects', () => {\n    type ServerError = Error & {\n      response: Response;\n      result: Record<string, any>;\n      statusCode: number;\n    };\n\n    type ServerParseError = Error & {\n      response: Response;\n      statusCode: number;\n      bodyText: string;\n    };\n\n    type Input = Error | ServerError | ServerParseError | undefined;\n\n    const networkError = new Error() as Input;\n\n    const message = match(networkError)\n      .with(\n        { statusCode: 401, name: P.string, message: P.string },\n        (x) => 'Not Authenticated'\n      )\n      .with(\n        { statusCode: 403, name: '', message: '' },\n        (x) => 'Permission Denied'\n      )\n      .otherwise(() => 'Network Error');\n\n    expect(message).toBe('Network Error');\n  });\n});\n"
  },
  {
    "path": "tests/variadic-tuples.test.ts",
    "content": "import { match, P } from '../src';\nimport { Equal, Expect } from '../src/types/helpers';\n\ndescribe('variadic tuples ([a, ...b[]])', () => {\n  describe('runtime', () => {\n    describe('match', () => {\n      it('[any ...any] pattern should match any non-empty array', () => {\n        const f = (xs: unknown[]) =>\n          match(xs)\n            .with([P.any, ...P.array()], () => 'non empty')\n            .otherwise(() => 'empty');\n\n        expect(f([])).toBe('empty');\n        expect(f([1])).toBe('non empty');\n        expect(f([1, 2])).toBe('non empty');\n        expect(f([1, 2, 3])).toBe('non empty');\n        expect(f(['1', '2', '3', '4'])).toBe('non empty');\n      });\n\n      it('[...any, any] pattern should match any non-empty array', () => {\n        const f = (xs: unknown[]) =>\n          match(xs)\n            .with([...P.array(), P.any], () => 'non empty')\n            .otherwise(() => 'empty');\n\n        expect(f([])).toBe('empty');\n        expect(f([1])).toBe('non empty');\n        expect(f([1, 2])).toBe('non empty');\n        expect(f([1, 2, 3])).toBe('non empty');\n        expect(f(['1', '2', '3', '4'])).toBe('non empty');\n      });\n\n      it('[any, ...any, any] patterns should match arrays with at least 2 elements', () => {\n        const f = (xs: unknown[]) =>\n          match(xs)\n            .with([P.any, ...P.array(), P.any], () => '>= 2')\n            .otherwise(() => '< 2');\n\n        expect(f([1])).toBe('< 2');\n        expect(f([1, 2])).toBe('>= 2');\n        expect(f([1, 2, 3])).toBe('>= 2');\n        expect(f(['1', '2', '3', '4'])).toBe('>= 2');\n      });\n\n      it('[number, ...string[]]', () => {\n        const f = (xs: unknown[]) =>\n          match(xs)\n            .with([P.number, ...P.array(P.string)], () => 'match')\n            .otherwise(() => \"doesn't match\");\n\n        expect(f([1])).toBe('match');\n        expect(f([1, 2])).toBe(\"doesn't match\");\n        expect(f([1, 2, 3])).toBe(\"doesn't match\");\n        expect(f([1, '2'])).toBe('match');\n        expect(f([1, '2', '3', '4'])).toBe('match');\n      });\n\n      it('[number, ...any, string]', () => {\n        const f = (xs: unknown[]) =>\n          match(xs)\n            .with([P.number, ...P.array(), P.string], () => 'match')\n            .otherwise(() => \"doesn't match\");\n\n        expect(f([1])).toBe(\"doesn't match\");\n        expect(f([1, 2])).toBe(\"doesn't match\");\n        expect(f([1, '2'])).toBe('match');\n        expect(f([1, 2, 3, '4'])).toBe('match');\n        expect(f([1, '1', '2', '3', '4'])).toBe('match');\n      });\n\n      it('[1, 2, 3, ...number[]]', () => {\n        const f = (xs: unknown[]) =>\n          match(xs)\n            .with([1, 2, 3, ...P.array(P.number)], () => 'match')\n            .otherwise(() => \"doesn't match\");\n\n        expect(f([1, 2, 3])).toBe('match');\n        expect(f([1, 2, 3, 4, 5, 6])).toBe('match');\n        expect(f([1])).toBe(\"doesn't match\");\n        expect(f([1, 2])).toBe(\"doesn't match\");\n        expect(f([1, 3, 2])).toBe(\"doesn't match\");\n        expect(f([1, 2, 3, 4, '5'])).toBe(\"doesn't match\");\n        expect(f([1, 2, 3, '4', 5])).toBe(\"doesn't match\");\n        expect(f([1, 2, 3, 4, '5', 6])).toBe(\"doesn't match\");\n      });\n\n      it('[...number[], 1, 2, 3]', () => {\n        const f = (xs: unknown[]) =>\n          match(xs)\n            .with([...P.array(P.number), 1, 2, 3], () => 'match')\n            .otherwise(() => \"doesn't match\");\n\n        expect(f([1, 2, 3])).toBe('match');\n        expect(f([4, 5, 6, 1, 2, 3])).toBe('match');\n        expect(f([1])).toBe(\"doesn't match\");\n        expect(f([1, 2])).toBe(\"doesn't match\");\n        expect(f([1, 3, 2])).toBe(\"doesn't match\");\n        expect(f([1, 2, 3, 4, 5])).toBe(\"doesn't match\");\n        expect(f(['4', 5, 1, 2, 3])).toBe(\"doesn't match\");\n        expect(f([4, '5', 1, 2, 3])).toBe(\"doesn't match\");\n        expect(f([4, '5', 6, 1, 2, 3])).toBe(\"doesn't match\");\n      });\n\n      it('[number, number ...boolean[], string, symbol]', () => {\n        const f = (xs: unknown[]) =>\n          match(xs)\n            .with(\n              [P.number, P.number, ...P.array(P.boolean), P.string, P.symbol],\n              () => 'match'\n            )\n            .otherwise(() => \"doesn't match\");\n\n        expect(f([1, 2, true, 'hello', 'yo'])).toBe(\"doesn't match\");\n        //                              ^ ❌\n        expect(f([1, 2, true, 3, Symbol('yo')])).toBe(\"doesn't match\");\n        //                    ^ ❌\n        expect(f([1, 2, 'true', 'str', Symbol('yo')])).toBe(\"doesn't match\");\n        //                ^ ❌\n        expect(f([1, '2', true, 'str', Symbol('yo')])).toBe(\"doesn't match\");\n        //            ^ ❌\n        expect(f(['1', 2, true, 'str', Symbol('yo')])).toBe(\"doesn't match\");\n        //         ^ ❌\n        expect(f([1, 2, true, 'str', Symbol('yo')])).toBe('match');\n        //       ^ ✅\n        expect(f([1, 2, true, false, true, 'str', Symbol('yo')])).toBe('match');\n        //       ^ ✅\n\n        expect(f([1, 2, true, 'false', true, 'str', Symbol('yo')])).toBe(\n          //                    ^ ❌\n          \"doesn't match\"\n        );\n      });\n    });\n\n    describe('select', () => {\n      it('[1, sel, 2, ...number[]]', () => {\n        const f = (xs: unknown[]) =>\n          match(xs)\n            .with(\n              [1, P.select(P.number), 2, ...P.array(P.number)],\n              (sel) => sel\n            )\n            .otherwise(() => 'no');\n\n        expect(f([1, 42, 2, 3])).toEqual(42);\n      });\n\n      it('[1, 2, ...sel(number)[]]', () => {\n        const f = (xs: unknown[]) =>\n          match(xs)\n            .with([1, 2, ...P.array(P.select(P.number))], (sel) => sel)\n            .otherwise(() => 'no');\n\n        expect(f([1, 2, 3, 4])).toEqual([3, 4]);\n      });\n\n      it('[...sel(number)[], 1, 2]', () => {\n        const f = (xs: unknown[]) =>\n          match(xs)\n            .with([...P.array(P.select(P.number)), 1, 2], (sel) => sel)\n            .otherwise(() => 'no');\n\n        expect(f([3, 4, 1, 2])).toEqual([3, 4]);\n      });\n\n      it('[sel(a), ...sel(b), sel(c)]', () => {\n        const f = (xs: unknown[]) =>\n          match(xs)\n            .with(\n              [\n                P.select('a', P.number),\n                ...P.array(P.select('b', P.number)),\n                P.select('c', P.string),\n              ],\n              (sel) => sel\n            )\n            .otherwise(() => 'no');\n\n        expect(f([42, 1, 2, 3, '!'])).toEqual({ a: 42, b: [1, 2, 3], c: '!' });\n      });\n    });\n  });\n\n  describe('types', () => {\n    it('unknown input', () => {\n      const xs: unknown[] = [1, 2, 3, 'a', 'b', 'c'];\n\n      match(xs)\n        .with([P.any, ...P.array()], (xs) => {\n          type t = Expect<Equal<typeof xs, [unknown, ...unknown[]]>>;\n          return [];\n        })\n        .otherwise(() => {\n          return [];\n        });\n\n      match(xs)\n        .with([...P.array(), 7], (xs) => {\n          type t = Expect<Equal<typeof xs, [...unknown[], number]>>;\n          return [];\n        })\n        .otherwise(() => {\n          return [];\n        });\n\n      match(xs)\n        .with([42, ...P.array(P.number)], (xs) => {\n          type t = Expect<Equal<typeof xs, [42, ...number[]]>>;\n          return [];\n        })\n        .otherwise(() => {\n          return [];\n        });\n\n      match(xs)\n        .with([42, ...P.array(P.number), '!' as const], (xs) => {\n          type t = Expect<Equal<typeof xs, [42, ...number[], '!']>>;\n          return [];\n        })\n        .otherwise(() => {\n          return [];\n        });\n\n      match(xs)\n        .with([1, 2, ...P.array(P.number)], (xs) => {\n          type t = Expect<Equal<typeof xs, [1, 2, ...number[]]>>;\n          return [];\n        })\n        .otherwise(() => {\n          return [];\n        });\n\n      match(xs)\n        .with([...P.array(P.string), 'a', 'b'], (xs) => {\n          type t = Expect<Equal<typeof xs, [...string[], 'a', 'b']>>;\n          return [];\n        })\n        .otherwise(() => {\n          return [];\n        });\n    });\n\n    it('known input', () => {\n      const xs: (string | number)[] = [1, 2, 3, 'a', 'b', 'c'];\n\n      match(xs)\n        .with([P.any, ...P.array()], (xs) => {\n          type t = Expect<\n            Equal<typeof xs, [string | number, ...(string | number)[]]>\n          >;\n          return [];\n        })\n        .otherwise(() => []);\n\n      match(xs)\n        .with([...P.array(), 7], (xs) => {\n          type t = Expect<Equal<typeof xs, [...(string | number)[], 7]>>;\n          return [];\n        })\n        .otherwise(() => []);\n\n      match(xs)\n        .with([42, ...P.array(P.number)], (xs) => {\n          type t = Expect<Equal<typeof xs, [42, ...number[]]>>;\n          return [];\n        })\n        .otherwise(() => []);\n\n      match(xs)\n        .with([42, ...P.array(P.number), 7], (xs) => {\n          type t = Expect<Equal<typeof xs, [42, ...number[], 7]>>;\n          return [];\n        })\n        .otherwise(() => []);\n\n      match(xs)\n        .with(\n          [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ...P.array(P.number), 7],\n          (xs) => {\n            type t = Expect<\n              Equal<typeof xs, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ...number[], 7]>\n            >;\n            return [];\n          }\n        )\n        .otherwise(() => []);\n\n      match(xs)\n        .with([...P.array(P.number), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], (xs) => {\n          type t = Expect<\n            Equal<typeof xs, [...number[], 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]>\n          >;\n          return [];\n        })\n        .otherwise(() => []);\n\n      match(xs)\n        .with(\n          [\n            1,\n            2,\n            3,\n            4,\n            5,\n            6,\n            7,\n            8,\n            9,\n            10,\n            ...P.array(P.number),\n            1,\n            2,\n            3,\n            4,\n            5,\n            6,\n            7,\n            8,\n            9,\n            10,\n          ],\n          (xs) => {\n            type t = Expect<\n              Equal<\n                typeof xs,\n                [\n                  1,\n                  2,\n                  3,\n                  4,\n                  5,\n                  6,\n                  7,\n                  8,\n                  9,\n                  10,\n                  ...number[],\n                  1,\n                  2,\n                  3,\n                  4,\n                  5,\n                  6,\n                  7,\n                  8,\n                  9,\n                  10\n                ]\n              >\n            >;\n            return [];\n          }\n        )\n        .otherwise(() => []);\n\n      match(xs)\n        .with([1, 2, ...P.array(P.number)], (xs) => {\n          type t = Expect<Equal<typeof xs, [1, 2, ...number[]]>>;\n          return [];\n        })\n        .otherwise(() => []);\n\n      match(xs)\n        .with([...P.array(P.string), 'a', 'b'], (xs) => {\n          type t = Expect<Equal<typeof xs, [...string[], 'a', 'b']>>;\n          return [];\n        })\n        .otherwise(() => []);\n    });\n\n    it('select', () => {\n      const xs: (string | number)[] = [1, 2, 3, 'a', 'b', 'c'];\n\n      match(xs)\n        .with([P.select(), ...P.array()], (xs) => {\n          type t = Expect<Equal<typeof xs, string | number>>;\n          return [];\n        })\n        .otherwise(() => []);\n\n      match(xs)\n        .with([...P.array(P.select()), 7], (xs) => {\n          type t = Expect<Equal<typeof xs, (string | number)[]>>;\n          return [];\n        })\n        .otherwise(() => []);\n\n      match(xs)\n        .with([42, ...P.array(P.select(P.number))], (xs) => {\n          type t = Expect<Equal<typeof xs, number[]>>;\n          return [];\n        })\n        .otherwise(() => []);\n\n      match(xs)\n        .with(\n          [P.select('head', 42), ...P.array(P.select('tail', P.number))],\n          (xs) => {\n            type t = Expect<Equal<typeof xs, { tail: number[]; head: 42 }>>;\n            return [];\n          }\n        )\n        .otherwise(() => []);\n\n      match(xs)\n        .with([1, 2, ...P.array(P.select(P.number))], (xs) => {\n          type t = Expect<Equal<typeof xs, number[]>>;\n          return [];\n        })\n        .otherwise(() => []);\n\n      match(xs).with(\n        [\n          P.select('a', 1),\n          P.select('b', 2),\n          ...P.array(P.select('c', P.number)),\n        ],\n        (xs) => {\n          type t = Expect<Equal<typeof xs, { c: number[]; a: 1; b: 2 }>>;\n          return [];\n        }\n      );\n      match(xs)\n        .with([1, P.select(2), ...P.array(P.number)], (xs) => {\n          type t = Expect<Equal<typeof xs, 2>>;\n          return [];\n        })\n        .otherwise(() => []);\n\n      match(xs)\n        .with([...P.array(P.select(P.string)), 'a'], (xs) => {\n          type t = Expect<Equal<typeof xs, string[]>>;\n          return [];\n        })\n        .otherwise(() => []);\n\n      match(xs).with(\n        [...P.array(P.select('inits', P.string)), P.select('last', 'a')],\n        (xs) => {\n          type t = Expect<Equal<typeof xs, { inits: string[]; last: 'a' }>>;\n          return [];\n        }\n      );\n      match(xs)\n        .with([...P.array(P.string), P.select()], (xs) => {\n          type t = Expect<Equal<typeof xs, string | number>>;\n          return [];\n        })\n        .otherwise(() => []);\n\n      match(xs)\n        .with([...P.array(P.select(P.string)), 'a', 'b'], (xs) => {\n          type t = Expect<Equal<typeof xs, string[]>>;\n          return [];\n        })\n        .otherwise(() => []);\n\n      match(xs)\n        .with([...P.array(P.string), P.select(2), 'b'], (xs) => {\n          type t = Expect<Equal<typeof xs, 2>>;\n          return [];\n        })\n        .otherwise(() => []);\n\n      match(xs)\n        .with(\n          [\n            ...P.array(P.select('a', P.string)),\n            P.select('b', 2),\n            P.select('c', 'b'),\n          ],\n          (xs) => {\n            type t = Expect<Equal<typeof xs, { a: string[]; b: 2; c: 'b' }>>;\n            return [];\n          }\n        )\n        .otherwise(() => []);\n\n      match(xs)\n        .with([42, ...P.array(P.select(P.number)), '!'], (xs) => {\n          type t = Expect<Equal<typeof xs, number[]>>;\n          return [];\n        })\n        .otherwise(() => []);\n\n      match(xs)\n        .with(\n          [\n            P.select('a', 42),\n            ...P.array(P.number.select('b')),\n            P.select('c', '!'),\n          ],\n          (xs) => {\n            type t = Expect<Equal<typeof xs, { b: number[]; a: 42; c: '!' }>>;\n            return [];\n          }\n        )\n        .otherwise(() => []);\n    });\n  });\n\n  describe('exhaustiveness checking', () => {\n    it('1 catch-all wildcards', () => {\n      const xs: (string | number)[] = [1, 2, 3, 'a', 'b', 'c'];\n\n      const throws = () =>\n        match([])\n          .with([P.any, ...P.array()], (xs) => {\n            return 'branch 1' as const;\n          })\n          // @ts-expect-error: empty list case missing\n          .exhaustive();\n\n      expect(() => throws()).toThrow();\n\n      const res = match(xs)\n        .with([P.any, ...P.array()], (xs) => {\n          return 'branch 1' as const;\n        })\n        .with([], (xs) => {\n          return 'branch 2' as const;\n        })\n        .exhaustive();\n\n      type t = Expect<Equal<typeof res, 'branch 1' | 'branch 2'>>;\n\n      expect(res).toBe('branch 1');\n    });\n\n    it('2 catch-all wildcards', () => {\n      const xs: (string | number)[] = [1, 2, 3, 'a', 'b', 'c'];\n\n      match(xs)\n        .with([P.any, P.any, ...P.array()], (xs) => {\n          return 'branch 1' as const;\n        })\n        // @ts-expect-error: empty list case missing\n        .exhaustive();\n\n      match(xs)\n        .with([P.any, P.any, ...P.array()], (xs) => {\n          return 'branch 1' as const;\n        })\n        .with([P.any, ...P.array()], (xs) => {\n          return 'branch 2' as const;\n        })\n        // @ts-expect-error: empty list case missing\n        .exhaustive();\n\n      const res = match(xs)\n        .with([P.any, P.any, ...P.array()], (xs) => {\n          return 'branch 1' as const;\n        })\n        .with([P.any, ...P.array()], (xs) => {\n          return 'branch 2' as const;\n        })\n        .with([], (xs) => {\n          return 'branch 3' as const;\n        })\n        .exhaustive();\n\n      type t = Expect<Equal<typeof res, 'branch 1' | 'branch 2' | 'branch 3'>>;\n\n      expect(res).toBe('branch 1');\n    });\n  });\n\n  describe('select', () => {\n    it('selection should work on the variadic part', () => {\n      const fn = (input: (number | string)[]) =>\n        match(input)\n          .with([1, 2, ...P.array(P.number).select()], (rest) => {\n            type t = Expect<Equal<typeof rest, number[]>>;\n            return ['branch 1', ...rest];\n          })\n          .with([1, 2, ...P.array(P.number).select(), 'end'], (rest) => {\n            type t = Expect<Equal<typeof rest, number[]>>;\n            return ['branch 2', ...rest];\n          })\n          .with(P.array(P.number.or(P.string)), (rest) => {\n            type t = Expect<Equal<typeof rest, (number | string)[]>>;\n            return 'otherwise';\n          })\n          .exhaustive();\n\n      expect(fn([1, 2, 3])).toEqual(['branch 1', 3]);\n      expect(fn([1, 2, 3, 4])).toEqual(['branch 1', 3, 4]);\n      expect(fn([1, 2, 23, 123, 'end'])).toEqual(['branch 2', 23, 123]);\n      expect(fn(['1', 2, 3, 4])).toEqual('otherwise');\n    });\n\n    it('variadic and array patterns should be threated differently', () => {\n      const fn = (input: (number | number[] | string)[]) =>\n        match(input)\n          .with([1, 2, ...P.array(P.number).select()], (rest) => {\n            type t = Expect<Equal<typeof rest, number[]>>;\n            return ['variadic 1', ...rest];\n          })\n          .with([1, 2, ...P.array(P.number).select(), 'end'], (rest) => {\n            type t = Expect<Equal<typeof rest, number[]>>;\n            return ['variadic 2', ...rest];\n          })\n          .with([1, 2, P.array(P.number).select()], (rest) => {\n            type t = Expect<Equal<typeof rest, number[]>>;\n            return ['array 1', ...rest];\n          })\n          .with([1, 2, P.array(P.number).select(), 'end'], (rest) => {\n            type t = Expect<Equal<typeof rest, number[]>>;\n            return ['array 2', ...rest];\n          })\n          .with(P.array(P.number.or(P.string).or(P.array())), (rest) => {\n            type t = Expect<Equal<typeof rest, (number | number[] | string)[]>>;\n            return 'otherwise';\n          })\n          .exhaustive();\n\n      expect(fn([1, 2, 3])).toEqual(['variadic 1', 3]);\n      expect(fn([1, 2, 3, 4])).toEqual(['variadic 1', 3, 4]);\n      expect(fn([1, 2, 23, 123, 'end'])).toEqual(['variadic 2', 23, 123]);\n      expect(fn([1, 2, [3, 4]])).toEqual(['array 1', 3, 4]);\n      expect(fn([1, 2, [23, 123], 'end'])).toEqual(['array 2', 23, 123]);\n      expect(fn(['1', 2, 3, 4])).toEqual('otherwise');\n    });\n  });\n});\n"
  },
  {
    "path": "tests/when.test.ts",
    "content": "import { Expect, Equal } from '../src/types/helpers';\nimport { match, P, Pattern } from '../src';\nimport { Option, State } from './types-catalog/utils';\n\ndescribe('when', () => {\n  it('should work for simple cases', () => {\n    const values = [\n      { value: 1, expected: false },\n      { value: -2, expected: false },\n      { value: 3, expected: false },\n      { value: 100, expected: false },\n      { value: 20, expected: true },\n      { value: 39, expected: true },\n    ];\n\n    values.forEach(({ value, expected }) => {\n      expect(\n        match(value)\n          .with(\n            P.when((x) => x > 10 && x < 50),\n            () => true\n          )\n          .otherwise(() => false)\n      ).toEqual(expected);\n    });\n  });\n\n  it('should narrow down the value type based on type guard', () => {\n    let n = 20;\n    const res = match(n)\n      .with(\n        P.when((x): x is 13 => x === 13),\n        (x) => {\n          type t = Expect<Equal<typeof x, 13>>;\n          return true;\n        }\n      )\n      .otherwise(() => false);\n\n    type t = Expect<Equal<typeof res, boolean>>;\n  });\n\n  it('should be able to correcly narrow a generic types', () => {\n    const map = <A, B>(option: Option<A>, mapper: (value: A) => B): Option<B> =>\n      match<Option<A>, Option<B>>(option)\n        .when(\n          (option): option is { kind: 'some'; value: A } =>\n            option.kind === 'some',\n          (option) => ({\n            kind: 'some',\n            value: mapper(option.value),\n          })\n        )\n        .when(\n          (option): option is { kind: 'none' } => option.kind === 'none',\n          (option) => option\n        )\n        .run();\n\n    const input = { kind: 'some' as const, value: 20 };\n    const expectedOutput = { kind: 'some' as const, value: `number is 20` };\n\n    const res = map(input, (x) => `number is ${x}`);\n\n    type t = Expect<Equal<typeof res, Option<string>>>;\n\n    expect(res).toEqual(expectedOutput);\n  });\n\n  it('should correctly infer the input type, even when used in another function pattern', () => {\n    const f = (x: { a: number[] }) =>\n      match(x)\n        .with(\n          {\n            a: P.array(\n              P.when((x) => {\n                type t = Expect<Equal<typeof x, number>>;\n                return true;\n              })\n            ),\n          },\n          () => 'true'\n        )\n        .otherwise(() => 'false');\n  });\n\n  it('should accept other values  than booleans in output', () => {\n    const f = (x: { a: number[] }) =>\n      match(x)\n        .with(\n          {\n            a: P.when(() => {\n              return 'anything truthy';\n            }),\n          },\n          () => 'true'\n        )\n        .otherwise(() => 'false');\n\n    expect(f({ a: [] })).toEqual('true');\n  });\n\n  describe('`with` with `when` clauses', () => {\n    it('should work for simple cases', () => {\n      const values: { value: State; expected: boolean }[] = [\n        { value: { status: 'success', data: 'yo' }, expected: false },\n        { value: { status: 'success', data: 'coucou' }, expected: true },\n        { value: { status: 'idle' }, expected: false },\n        { value: { status: 'loading' }, expected: false },\n      ];\n\n      values.forEach(({ value, expected }) => {\n        expect(\n          match(value)\n            .with(\n              { status: 'success' },\n              (x) => x.data.length > 3,\n              (x) => {\n                type t = Expect<\n                  Equal<typeof x, { status: 'success'; data: string }>\n                >;\n                return true;\n              }\n            )\n            .with(\n              { status: 'success', data: P.select('data') },\n              (x) => x.data.length > 3 && x.data.length < 10,\n              (x) => {\n                type t = Expect<Equal<typeof x, { data: string }>>;\n                return true;\n              }\n            )\n            .with(\n              { status: 'success', data: P.select('data') },\n              (x) =>\n                x.data.length > 3 && x.data.length < 10 && x.data.length % 2,\n              (x) => {\n                type t = Expect<Equal<typeof x, { data: string }>>;\n                return true;\n              }\n            )\n            .otherwise(() => false)\n        ).toEqual(expected);\n      });\n    });\n\n    it('type should be refined in each guard clause', () => {\n      const values: { value: number | string; expected: string }[] = [\n        { value: -1, expected: 'x: number' },\n        { value: 2, expected: '2' },\n        { value: 5, expected: '2 < x < 10' },\n        { value: 100, expected: 'x: number' },\n        { value: '100', expected: '2 < x.length < 10' },\n        { value: 'Gabriel Vergnaud', expected: 'x: string' },\n      ];\n\n      values.forEach(({ value, expected }) => {\n        const res = match(value)\n          .with(\n            P.any,\n            (x): x is 2 => x === 2,\n            (x) => {\n              type t = Expect<Equal<typeof x, 2>>;\n              return '2';\n            }\n          )\n          .with(\n            P.string,\n            (x) => x.length > 2 && x.length < 10,\n            () => '2 < x.length < 10'\n          )\n          .with(\n            P.number,\n            (x) => x > 2 && x < 10,\n            () => '2 < x < 10'\n          )\n          .with(\n            P.any,\n            (x): x is number => typeof x === 'number',\n            (x) => {\n              type t = Expect<Equal<typeof x, number>>;\n              return 'x: number';\n            }\n          )\n          .with(P.string, () => 'x: string')\n          .exhaustive();\n\n        expect(res).toEqual(expected);\n      });\n    });\n  });\n\n  it('should narrow the type of the input based on the pattern', () => {\n    type Option<T> = { type: 'some'; value: T } | { type: 'none' };\n\n    const optionalFizzBuzz = (\n      optionalNumber: Option<{\n        opt?: 'x' | 'y';\n        list: {\n          test: 'a' | 'b';\n          sublist: ('z' | 'w')[];\n          prop: string;\n          maybe?: string | number;\n        }[];\n        coords: { x: 'left' | 'right'; y: 'top' | 'bottom' };\n      }>\n    ) =>\n      match(optionalNumber)\n        .with(\n          {\n            type: 'some',\n            value: {\n              list: P.array({\n                test: 'a',\n                sublist: ['w'],\n                maybe: P.string.optional(),\n                prop: P.when((x) => {\n                  type t = Expect<Equal<typeof x, string>>;\n                  return true;\n                }),\n              }),\n              opt: P.optional('x'),\n            },\n          },\n          (x) => {\n            type t = Expect<\n              Equal<\n                typeof x,\n                {\n                  type: 'some';\n                  value: {\n                    opt?: 'x' | undefined;\n                    list: {\n                      test: 'a';\n                      sublist: ['w'];\n                      prop: string;\n                      maybe?: string | undefined;\n                    }[];\n                    coords: {\n                      x: 'left' | 'right';\n                      y: 'top' | 'bottom';\n                    };\n                  };\n                }\n              >\n            >;\n            return 'ok';\n          }\n        )\n        .with(\n          {\n            type: 'some',\n            value: {\n              coords: P.not({ x: 'left' }),\n            },\n          },\n          (x) => {\n            type t = Expect<\n              Equal<\n                (typeof x)['value']['coords'],\n                {\n                  y: 'top' | 'bottom';\n                  x: 'right';\n                }\n              >\n            >;\n\n            return 'ok';\n          }\n        )\n        .with(\n          {\n            type: 'some',\n            value: {\n              list: P.array({ test: 'a', prop: P.select() }),\n            },\n          },\n          (x) => {\n            type t = Expect<Equal<typeof x, string[]>>;\n          }\n        )\n        .with({ type: 'none' }, () => null)\n        .with({ type: 'some' }, () => 'ok')\n        .exhaustive();\n  });\n\n  it('should narrow the type of the input based on the pattern', () => {\n    const optionalFizzBuzz = (optionalNumber: Option<number>) =>\n      match(optionalNumber)\n        // You can add up to 3 guard functions after your\n        // pattern. They must all return true for the\n        // handler to be executed.\n        .with(\n          { kind: 'some' },\n          // `someNumber` is inferred to be a { kind: \"some\"; value: number }\n          // based on the pattern provided as first argument.\n          (someNumber) =>\n            someNumber.value % 5 === 0 && someNumber.value % 3 === 0,\n          () => 'fizzbuzz'\n        )\n        .with(\n          {\n            kind: 'some',\n          },\n          // you can also use destructuring\n          ({ value }) => value % 5 === 0,\n          () => 'buzz'\n        )\n\n        // Or you can use a `when` pattern, to apply your guard to\n        // a subset of your input.\n        .with(\n          {\n            kind: 'some',\n            value: Pattern.when((value) => value % 3 === 0),\n          },\n          () => 'fizz'\n        )\n        // for all other numbers, just convert them to a string.\n        .with({ kind: 'some' }, ({ value }) => value.toString())\n        // if it's a none, return \"nope\"\n        .with({ kind: 'none' }, () => 'nope')\n        .exhaustive();\n  });\n\n  it('should be possible to hard code type parameters to P.when', () => {\n    const regex = <input>(expr: RegExp) =>\n      P.when<\n        input | string, // input\n        string, // narrowed value\n        never // types excluded\n      >((x): x is string => typeof x === 'string' && expr.test(x));\n\n    type Input = string | { prop: string | number };\n\n    expect(\n      match<Input>('Hello')\n        .with(regex(/^H/), () => true)\n        .with({ prop: regex(/^H/) }, (x) => {\n          type t = Expect<Equal<typeof x, { prop: string }>>;\n          return true;\n        })\n        // @ts-expect-error\n        .exhaustive()\n    ).toBe(true);\n  });\n\n  it('should be possible to do some manipulations on the input type', () => {\n    const notString = <input>() =>\n      P.when<\n        input | string, // input\n        Exclude<input, string>, // narrowed value\n        never // types excluded\n      >((x): x is Exclude<input, string> => typeof x !== 'string');\n\n    type Input = { prop: string | number };\n\n    expect(\n      match<Input>({ prop: 20 })\n        .with({ prop: notString() }, (x) => {\n          type t = Expect<Equal<typeof x, { prop: number }>>;\n          return true;\n        })\n        // @ts-expect-error\n        .exhaustive()\n    ).toBe(true);\n  });\n\n  it('issue #153: P.when should preserve undefined.', () => {\n    type Data = { digit: number };\n\n    type Input = {\n      data: Data | undefined;\n    };\n\n    const input: Input = { data: undefined };\n\n    const result = match(input)\n      .with(\n        {\n          data: P.when((data) => {\n            type t = Expect<Equal<typeof data, Data | undefined>>;\n            return data ? data.digit > 5 : 0;\n          }),\n        },\n        () => 'digit is more than 5'\n      )\n      .otherwise(() => 'digit is less than 5');\n\n    expect(result).toBe('digit is less than 5');\n  });\n});\n"
  },
  {
    "path": "tests/wildcards.test.ts",
    "content": "import { Expect, Equal } from '../src/types/helpers';\nimport { match, P } from '../src';\nimport { Blog } from './types-catalog/utils';\nimport { InvertPattern } from '../src/types/InvertPattern';\nimport { ExtractPreciseValue } from '../src/types/ExtractPreciseValue';\n\ndescribe('wildcards', () => {\n  it('should match String wildcards', () => {\n    const res = match<string | number | boolean | null | undefined>('')\n      .with(NaN, () => '')\n      .with(P.string, (x) => {\n        type t = Expect<Equal<typeof x, string>>;\n        return true;\n      })\n      .otherwise(() => false);\n\n    expect(res).toEqual(true);\n  });\n\n  it('should match Number wildcards', () => {\n    const res = match<string | number | boolean | null | undefined>(2)\n      .with(P.number, (x) => {\n        type t = Expect<Equal<typeof x, number>>;\n        return true;\n      })\n      .otherwise(() => false);\n\n    expect(res).toEqual(true);\n  });\n\n  it('should match Boolean wildcards', () => {\n    const res = match<string | number | boolean | null | undefined>(true)\n      .with(P.boolean, (x) => {\n        type t = Expect<Equal<typeof x, boolean>>;\n        return true;\n      })\n      .otherwise(() => false);\n\n    expect(res).toEqual(true);\n  });\n\n  it('should match nullish wildcard', () => {\n    const res = match<string | number | boolean | null | undefined>(null)\n      .with(P.nullish, (x) => {\n        type t = Expect<Equal<typeof x, null | undefined>>;\n        return true;\n      })\n      .otherwise(() => false);\n\n    const res2 = match<string | number | boolean | null | undefined>(undefined)\n      .with(P.nullish, (x) => {\n        type t = Expect<Equal<typeof x, null | undefined>>;\n        return true;\n      })\n      .otherwise(() => false);\n\n    expect(res).toEqual(true);\n    expect(res2).toEqual(true);\n  });\n\n  describe('P.nonNullable', () => {\n    it('should narrow primitive types correctly', () => {\n      type Input = string | number | boolean | null | undefined;\n      const res = match<Input>(false)\n        .with(P.nonNullable, (x) => {\n          type t = Expect<Equal<typeof x, string | number | boolean>>;\n          return true;\n        })\n        .otherwise(() => false);\n\n      const res2 = match<0 | 1 | 2 | null>(0)\n        .with(P.nonNullable, (x) => {\n          type t = Expect<Equal<typeof x, 0 | 1 | 2>>;\n          return true;\n        })\n        .with(null, () => false)\n        .exhaustive();\n\n      expect(res).toEqual(true);\n      expect(res2).toEqual(true);\n    });\n\n    it('should narrow object types correctly', () => {\n      type Input =\n        | {\n            __typename: 'ValidationRejection';\n            fields: string[];\n          }\n        | {\n            __typename: 'ValidationRejection';\n          };\n\n      const pattern = {\n        __typename: 'ValidationRejection',\n        fields: P.nonNullable,\n      } as const;\n      type X = InvertPattern<typeof pattern, Input>;\n      type Y = ExtractPreciseValue<Input, X>;\n\n      const fn = (data: Input) =>\n        match(data)\n          .with(\n            { __typename: 'ValidationRejection', fields: P.nonNullable },\n            ({ fields }) => {\n              type t = Expect<Equal<typeof fields, string[]>>;\n              return 'matched';\n            }\n          )\n          .otherwise(() => 'did not match');\n\n      expect(fn({ __typename: 'ValidationRejection' })).toBe('did not match');\n      expect(fn({ __typename: 'ValidationRejection', fields: [] })).toBe(\n        'matched'\n      );\n    });\n\n    it('combined with exhaustive, it should consider all values except null and undefined to be handled', () => {\n      const fn1 = (input: string | number | null | undefined) =>\n        match(input)\n          .with(P.nonNullable, (x) => {\n            type t = Expect<Equal<typeof x, string | number>>;\n          })\n          .with(P.nullish, () => {})\n          // should type-check\n          .exhaustive();\n\n      const fn2 = (input: { nested: string | number | null | undefined }) =>\n        match(input)\n          .with({ nested: P.nonNullable }, (x) => {\n            type t = Expect<Equal<typeof x, { nested: string | number }>>;\n          })\n          .with({ nested: P.nullish }, (x) => {\n            type t = Expect<Equal<typeof x, { nested: null | undefined }>>;\n          })\n          // should type-check\n          .exhaustive();\n    });\n  });\n\n  it('should match String, Number and Boolean wildcards', () => {\n    // Will be { id: number, title: string } | { errorMessage: string }\n    let httpResult = {\n      id: 20,\n      title: 'hellooo',\n    }; /* API logic. */\n\n    const res = match<any, Blog | Error>(httpResult)\n      .with({ id: P.number, title: P.string }, (r) => ({\n        id: r.id,\n        title: r.title,\n      }))\n      .with({ errorMessage: P.string }, (r) => new Error(r.errorMessage))\n      .otherwise(() => new Error('Client parse error'));\n\n    expect(res).toEqual({\n      id: 20,\n      title: 'hellooo',\n    });\n  });\n\n  it('should infer correctly negated String wildcards', () => {\n    const res = match<string | number | boolean>('')\n      .with(P.not(P.string), (x) => {\n        type t = Expect<Equal<typeof x, number | boolean>>;\n        return true;\n      })\n      .otherwise(() => false);\n\n    expect(res).toEqual(false);\n  });\n\n  it('should infer correctly negated Number wildcards', () => {\n    const res = match<string | number | boolean>(2)\n      .with(P.not(P.number), (x) => {\n        type t = Expect<Equal<typeof x, string | boolean>>;\n        return true;\n      })\n      .otherwise(() => false);\n\n    expect(res).toEqual(false);\n  });\n\n  it('should infer correctly negated Boolean wildcards', () => {\n    const res = match<string | number | boolean>(true)\n      .with(P.not(P.boolean), (x) => {\n        type t = Expect<Equal<typeof x, string | number>>;\n        return true;\n      })\n      .otherwise(() => false);\n\n    expect(res).toEqual(false);\n  });\n\n  it(\"when used as an object property pattern, it shouldn't match if the key isn't defined on the object.\", () => {\n    type Id = { teamId: number } | { storeId: number };\n\n    const selectedId: Id = { teamId: 1 };\n\n    const res = match<Id>(selectedId)\n      .with({ storeId: P._ }, () => 'storeId')\n      .with({ teamId: P._ }, () => 'teamId')\n      .exhaustive();\n\n    expect(res).toEqual('teamId');\n  });\n\n  describe('catch all', () => {\n    const allValueTypes = [\n      undefined,\n      null,\n      Symbol(2),\n      2,\n      'string',\n      true,\n      () => {},\n      {},\n      [],\n      new Map(),\n      new Set(),\n    ];\n\n    allValueTypes.forEach((value) => {\n      it(`should match ${typeof value} values`, () => {\n        expect(\n          match(value)\n            .with(P._, () => 'yes')\n            .exhaustive()\n        ).toEqual('yes');\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"ESNext\",\n    \"declaration\": true,\n    \"target\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"strict\": true,\n    \"outDir\": \"dist/\",\n    \"skipLibCheck\": true,\n    \"esModuleInterop\": true\n  },\n  \"include\": [\"src/\"],\n  \"exclude\": [\"tests/\", \"dist/\", \"examples/\", \"node_modules/\"]\n}\n"
  }
]