Full Code of gvergnaud/ts-pattern for AI

main f66fc061fde4 cached
99 files
590.3 KB
167.6k tokens
1440 symbols
1 requests
Download .txt
Showing preview only (621K chars total). Download the full file or copy to clipboard to get everything.
Repository: gvergnaud/ts-pattern
Branch: main
Commit: f66fc061fde4
Files: 99
Total size: 590.3 KB

Directory structure:
gitextract_ejzj_xdd/

├── .github/
│   ├── FUNDING.yml
│   └── ISSUE_TEMPLATE/
│       ├── bug_report.md
│       └── feature_request.md
├── .gitignore
├── .prettierrc
├── LICENSE
├── README.md
├── benchmarks/
│   ├── always-last-digit.ts
│   ├── nested-objects.ts
│   ├── package.json
│   └── random-digit.ts
├── docs/
│   ├── roadmap.md
│   ├── v3-to-v4-migration-guide.md
│   └── v4-to-v5-migration-guide.md
├── examples/
│   ├── gif-fetcher/
│   │   ├── package.json
│   │   ├── public/
│   │   │   └── index.html
│   │   ├── src/
│   │   │   ├── App.tsx
│   │   │   ├── constants.ts
│   │   │   ├── index.tsx
│   │   │   ├── searchGif.ts
│   │   │   └── styles.css
│   │   └── tsconfig.json
│   └── one-file-demo/
│       ├── one-file-demo.ts
│       ├── package.json
│       └── tsconfig.json
├── jest.config.cjs
├── jsr.json
├── package.json
├── scripts/
│   └── generate-cts.sh
├── src/
│   ├── errors.ts
│   ├── index.ts
│   ├── internals/
│   │   ├── helpers.ts
│   │   └── symbols.ts
│   ├── is-matching.ts
│   ├── match.ts
│   ├── patterns.ts
│   └── types/
│       ├── BuildMany.ts
│       ├── DeepExclude.ts
│       ├── DistributeUnions.ts
│       ├── ExtractPreciseValue.ts
│       ├── FindSelected.ts
│       ├── InvertPattern.ts
│       ├── IsMatching.ts
│       ├── Match.ts
│       ├── Pattern.ts
│       ├── helpers.ts
│       └── index.ts
├── tests/
│   ├── bigints.test.ts
│   ├── branded-nominal-types.test.ts
│   ├── build-many.test.ts
│   ├── chainable.test.ts
│   ├── deep-exclude.test.ts
│   ├── distribute-unions.test.ts
│   ├── exhaustive-fallback.test.ts
│   ├── exhaustive-match.test.ts
│   ├── extract-precise-value.test.ts
│   ├── find-selected.test.ts
│   ├── generics.test.ts
│   ├── helpers.test.ts
│   ├── infer.test.ts
│   ├── instance-of.test.ts
│   ├── intersection-and-union.test.ts
│   ├── invert-pattern.test.ts
│   ├── is-matching.test.ts
│   ├── large-exhaustive.test.ts
│   ├── lists.test.ts
│   ├── maps.test.ts
│   ├── matcher-protocol.test.ts
│   ├── multiple-patterns.test.ts
│   ├── narrow.test.ts
│   ├── nesting.test.ts
│   ├── not.test.ts
│   ├── numbers.test.ts
│   ├── objects.test.ts
│   ├── optional-props.test.ts
│   ├── optional.test.ts
│   ├── otherwise.test.ts
│   ├── output-type.test.ts
│   ├── pattern.test.ts
│   ├── primitive-values.test.ts
│   ├── readonly.test.ts
│   ├── real-world.test.ts
│   ├── record.test.ts
│   ├── return-type.test.ts
│   ├── select.test.ts
│   ├── sets.test.ts
│   ├── strings.test.ts
│   ├── tsconfig.json
│   ├── tuples.test.ts
│   ├── type-error.test.ts
│   ├── type-is-matching.test.ts
│   ├── types-catalog/
│   │   ├── definition.ts
│   │   └── utils.ts
│   ├── types.test.ts
│   ├── unions.test.ts
│   ├── variadic-tuples.test.ts
│   ├── when.test.ts
│   └── wildcards.test.ts
└── tsconfig.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms

github: [gvergnaud] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
# patreon: # Replace with a single Patreon username
# open_collective: # Replace with a single Open Collective username
# ko_fi: # Replace with a single Ko-fi username
# tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
# community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
# liberapay: # Replace with a single Liberapay username
# issuehunt: # Replace with a single IssueHunt username
# otechie: # Replace with a single Otechie username
# lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
# custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']


================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''

---

**Describe the bug**
A clear and concise description of what the bug is.

**TypeScript playground with a minimal reproduction case**

Example: [Playground](https://www.typescriptlang.org/play/?#code/JYWwDg9gTgLgBAbziAhjAxgCwDRwApwC+cAZlBCHAOQwDOAtGGjAKZQB2VAUFwPS9wA6lGCs4ATwgBXKHCgsw5OOhS0WAOi5A)

**Versions**
- TypeScript version: x.x.x
- ts-pattern version: x.x.x
- environment: browser + version / node version / deno version


================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: ''

---

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
Add any other context or screenshots about the feature request here.


================================================
FILE: .gitignore
================================================
.DS_Store
node_modules
npm-debug.log
lib
dist
notes.md
.vscode/
tracing_output_folder/
trace/
*.tgz

================================================
FILE: .prettierrc
================================================
{
    "singleQuote": true
}

================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2021 Gabriel Vergnaud

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
<h1 align="center">TS-Pattern</h1>

<p align="center">
The exhaustive Pattern Matching library for <a href="https://github.com/microsoft/TypeScript">TypeScript</a>
with smart type inference.
</p>

<p align="center">
  <a href="https://www.npmjs.com/package/ts-pattern">
    <img src="https://img.shields.io/npm/dm/ts-pattern.svg" alt="downloads" height="18">
  </a>
  <a href="https://www.npmjs.com/package/ts-pattern">
    <img src="https://img.shields.io/npm/v/ts-pattern.svg" alt="npm version" height="18">
  </a>
  <a href="https://github.com/gvergnaud/ts-pattern">
    <img src="https://img.shields.io/npm/l/ts-pattern.svg" alt="MIT license" height="18">
  </a>
</p>

```tsx
import { match, P } from 'ts-pattern';

type Data =
  | { type: 'text'; content: string }
  | { type: 'img'; src: string };

type Result =
  | { type: 'ok'; data: Data }
  | { type: 'error'; error: Error };

const result: Result = ...;

const html = match(result)
  .with({ type: 'error' }, () => <p>Oups! An error occured</p>)
  .with({ type: 'ok', data: { type: 'text' } }, (res) => <p>{res.data.content}</p>)
  .with({ type: 'ok', data: { type: 'img', src: P.select() } }, (src) => <img src={src} />)
  .exhaustive();
```

## About

Write **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**.

![ts-pattern](https://user-images.githubusercontent.com/9265418/231688650-7cd957a9-8edc-4db8-a5fe-61e1c2179d91.gif)

<p align="center"><i>Animation by <a target="_blank" href="https://twitter.com/nicoespeon/status/1644342570389061634?s=20">@nicoespeon</a></i></p>

## Features

- 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.
- **Typesafe**, with helpful [type inference](#type-inference).
- **Exhaustiveness checking** support, enforcing that you are matching every possible case with [`.exhaustive()`](#exhaustive).
- Use [patterns](#patterns) to **validate** the shape of your data with [`isMatching`](#ismatching).
- **Expressive API**, with catch-all and type specific **wildcards**: [`P._`](#p_-wildcard), [`P.string`](#pstring-wildcard), [`P.number`](#pnumber-wildcard), etc.
- Supports [**predicates**](#pwhen-patterns), [**unions**](#punion-patterns), [**intersections**](#pintersection-patterns) and [**exclusion**](#pnot-patterns) patterns for non-trivial cases.
- Supports properties selection, via the [`P.select(name?)`](#pselect-patterns) function.
- Tiny bundle footprint ([**only ~2kB**](https://bundlephobia.com/package/ts-pattern)).

## What is Pattern Matching?

[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.

Pattern 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.

Read 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)

## Installation

Via npm

```sh
npm install ts-pattern
```

You can also use your favorite package manager:

```sh
pnpm add ts-pattern
# OR
yarn add ts-pattern
# OR
bun add ts-pattern
# OR
npx jsr add @gabriel/ts-pattern
```

## Want to become a TypeScript Expert?

Check 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!

# Documentation

- [Sandbox examples](#sandbox-examples)
- [Getting Started](#getting-started)
- [API Reference](#api-reference)
  - [`match`](#match)
  - [`.with`](#with)
  - [`.when`](#when)
  - [`.returnType`](#returntype)
  - [`.exhaustive`](#exhaustive)
  - [`.otherwise`](#otherwise)
  - [`.narrow`](#narrow)
  - [`isMatching`](#ismatching)
  - [Patterns](#patterns)
    - [Literals](#literals)
    - [Wildcards](#wildcards)
    - [Objects](#objects)
    - [Tuples (arrays)](#tuples-arrays)
    - [`P.array` patterns](#parray-patterns)
    - [`P.record` patterns](#precord-patterns)
    - [`P.set`](#pset-patterns)
    - [`P.map`](#pmap-patterns)
    - [`P.when` patterns](#pwhen-patterns)
    - [`P.not` patterns](#pnot-patterns)
    - [`P.select` patterns](#pselect-patterns)
    - [`P.optional` patterns](#poptional-patterns)
    - [`P.instanceOf` patterns](#pinstanceof-patterns)
    - [`P.union` patterns](#punion-patterns)
    - [`P.intersection` patterns](#pintersection-patterns)
    - [`P.string` predicates](#pstring-predicates)
    - [`P.number` and `P.bigint` predicates](#pnumber-and-pbigint-predicates)
  - [Types](#types)
    - [`P.infer`](#pinfer)
    - [`P.Pattern`](#pPattern)
    - [Type inference](#type-inference)
- [Inspirations](#inspirations)

## Sandbox examples

- [Basic Demo](https://stackblitz.com/edit/vitejs-vite-qrk8po?file=src%2Fexamples%2Fbasic.tsx)
- [React gif fetcher app Demo](https://stackblitz.com/edit/ts-pattern-gifs?file=src%2FApp.tsx)
- [React.useReducer Demo](https://stackblitz.com/edit/ts-pattern-reducer?file=src%2FApp.tsx)
- [Handling untyped API response Demo](https://stackblitz.com/edit/vitejs-vite-qrk8po?file=src%2Fexamples%2Fapi.tsx)
- [`P.when` Guard Demo](https://stackblitz.com/edit/vitejs-vite-qrk8po?file=src%2Fexamples%2Fwhen.tsx)
- [`P.not` Pattern Demo](https://stackblitz.com/edit/vitejs-vite-qrk8po?file=src%2Fexamples%2Fnot.tsx)
- [`P.select` Pattern Demo](https://stackblitz.com/edit/vitejs-vite-qrk8po?file=src%2Fexamples%2Fselect.tsx)
- [`P.union` Pattern Demo](https://stackblitz.com/edit/vitejs-vite-qrk8po?file=src%2Fexamples%2Funion.tsx)

## Getting Started

As an example, let's create a state reducer for a frontend application that fetches some data.

### Example: a state reducer with ts-pattern

Our application can be in four different states: `idle`, `loading`,
`success` and `error`. Depending on which state we are in, some events
can occur. Here are all the possible types of event our application
can respond to: `fetch`, `success`, `error` and `cancel`.

I use the word `event` but you can replace it with `action` if you are used
to Redux's terminology.

```ts
type State =
  | { status: 'idle' }
  | { status: 'loading'; startTime: number }
  | { status: 'success'; data: string }
  | { status: 'error'; error: Error };

type Event =
  | { type: 'fetch' }
  | { type: 'success'; data: string }
  | { type: 'error'; error: Error }
  | { type: 'cancel' };
```

Even though our application can handle 4 events, **only a subset** of these
events **make sense for each given state**. For instance we can only `cancel`
a request if we are currently in the `loading` state.
To 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.

This 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:

<!-- prettier-ignore -->
```ts
import { match, P } from 'ts-pattern';

const reducer = (state: State, event: Event) =>
  match([state, event])
    .returnType<State>()
    .with(
      [{ status: 'loading' }, { type: 'success' }],
      ([_, event]) => ({ status: 'success', data: event.data })
    )
    .with(
      [{ status: 'loading' }, { type: 'error', error: P.select() }],
      (error) => ({ status: 'error', error })
    )
    .with(
      [{ status: P.not('loading') }, { type: 'fetch' }],
      () => ({ status: 'loading', startTime: Date.now() })
    )
    .with(
      [
        {
          status: 'loading',
          startTime: P.when((t) => t + 2000 < Date.now()),
        },
        { type: 'cancel' },
      ],
      () => ({ status: 'idle' })
    )
    .with(P._, () => state)
    .exhaustive();
```

There's a lot going on, so **let's go through this code bit by bit:**

### match(value)

`match` takes a value and returns a [_builder_](https://en.wikipedia.org/wiki/Builder_pattern) on which you can add your pattern matching cases.

<!-- prettier-ignore -->
```ts
match([state, event])
```

It'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.

### .returnType\<OutputType\>()

`.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>`.

```ts
  .returnType<State>()
```

Here, we use this method to make sure all branches return a valid `State` object.

### .with(pattern, handler)

Then we add a first `with` clause:

```ts
  .with(
    [{ status: 'loading' }, { type: 'success' }],
    ([state, event]) => ({
      // `state` is inferred as { status: 'loading' }
      // `event` is inferred as { type: 'success', data: string }
      status: 'success',
      data: event.data,
    })
  )
```

The first argument is the **pattern**: the **shape of value** you expect for this branch.

The second argument is the **handler function**: the code **branch** that will be called if the input value matches the pattern.

The handler function takes the input value as first parameter with its type **narrowed down** to what the pattern matches.

### P.select(name?)

In the second `with` clause, we use the `P.select` function:

```ts
  .with(
    [
      { status: 'loading' },
      { type: 'error', error: P.select() }
    ],
    (error) => ({ status: 'error', error })
  )
```

`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.

Since 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:

```ts
  .with(
    [
      { status: 'loading' },
      { type: 'error', error: P.select() }
    ],
    (error, stateAndEvent) => {
      // error: Error
      // stateAndEvent: [{ status: 'loading' }, { type: 'error', error: Error }]
    }
  )
```

In 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**:

```ts
.with(
    [
      { status: 'success', data: P.select('prevData') },
      { type: 'error', error: P.select('err') }
    ],
    ({ prevData, err }) => {
      // Do something with (prevData: string) and (err: Error).
    }
  )
```

Each named selection will be injected inside a `selections` object, passed as first argument to the handler function. Names can be any strings.

### P.not(pattern)

If 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:

```ts
  .with(
    [{ status: P.not('loading') }, { type: 'fetch' }],
    () => ({ status: 'loading' })
  )
```

### `P.when()` and guard functions

Sometimes, 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`.

With TS-Pattern, there are two ways to use a guard function:

- use `P.when(<guard function>)` inside one of your patterns
- pass it as second parameter to `.with(...)`

#### using P.when(predicate)

```ts
  .with(
    [
      {
        status: 'loading',
        startTime: P.when((t) => t + 2000 < Date.now()),
      },
      { type: 'cancel' },
    ],
    () => ({ status: 'idle' })
  )
```

#### Passing a guard function to `.with(...)`

`.with` optionally accepts a guard function as second parameter, between
the `pattern` and the `handler` callback:

```ts
  .with(
    [{ status: 'loading' }, { type: 'cancel' }],
    ([state, event]) => state.startTime + 2000 < Date.now(),
    () => ({ status: 'idle' })
  )
```

This pattern will only match if the guard function returns `true`.

### the `P._` wildcard

`P._` will match any value. You can use it either at the top level, or within another pattern.

```ts
  .with(P._, () => state)

  // You could also use it inside another pattern:
  .with([P._, P._], () => state)

  // at any level:
  .with([P._, { type: P._ }], () => state)

```

### .exhaustive(), .otherwise() and .run()

```ts
  .exhaustive();
```

`.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.

Note 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.

Alternatively, you can use `.otherwise()`, which takes an handler function returning a default value. `.otherwise(handler)` is equivalent to `.with(P._, handler).exhaustive()`.

```ts
  .otherwise(() => state);
```

### Matching several patterns

As you may know, `switch` statements allow handling several cases with
the same code block:

```ts
switch (type) {
  case 'text':
  case 'span':
  case 'p':
    return 'text';

  case 'btn':
  case 'button':
    return 'button';
}
```

Similarly, ts-pattern lets you pass several patterns to `.with()` and if
one of these patterns matches your input, the handler function will be called:

```ts
const sanitize = (name: string) =>
  match(name)
    .with('text', 'span', 'p', () => 'text')
    .with('btn', 'button', () => 'button')
    .otherwise(() => name);

sanitize('span'); // 'text'
sanitize('p'); // 'text'
sanitize('button'); // 'button'
```

As you might expect, this also works with more complex patterns than strings and exhaustiveness checking works as well.

## API Reference

### `match`

```ts
match(value);
```

Create a `Match` object on which you can later call `.with`, `.when`, `.otherwise` and `.run`.

#### Signature

```ts
function match<TInput, TOutput>(input: TInput): Match<TInput, TOutput>;
```

#### Arguments

- `input`
  - **Required**
  - the input value your patterns will be tested against.

### `.with`

```ts
match(...)
  .with(pattern, [...patterns], handler)
```

#### Signature

```ts
function with(
  pattern: Pattern<TInput>,
  handler: (selections: Selections<TInput>, value: TInput) => TOutput
): Match<TInput, TOutput>;

// Overload for multiple patterns
function with(
  pattern1: Pattern<TInput>,
  ...patterns: Pattern<TInput>[],
  // no selection object is provided when using multiple patterns
  handler: (value: TInput) => TOutput
): Match<TInput, TOutput>;

// Overload for guard functions
function with(
  pattern: Pattern<TInput>,
  when: (value: TInput) => unknown,
  handler: (
    selection: Selection<TInput>,
    value: TInput
  ) => TOutput
): Match<TInput, TOutput>;
```

#### Arguments

- `pattern: Pattern<TInput>`
  - **Required**
  - The pattern your input must match for the handler to be called.
  - [See all valid patterns below](#patterns)
  - If you provide several patterns before providing the `handler`, the `with` clause will match if one of the patterns matches.
- `when: (value: TInput) => unknown`
  - Optional
  - Additional condition the input must satisfy for the handler to be called.
  - The input will match if your guard function returns a truthy value.
  - `TInput` might be narrowed to a more precise type using the `pattern`.
- `handler: (selections: Selections<TInput>, value: TInput) => TOutput`
  - **Required**
  - Function called when the match conditions are satisfied.
  - All handlers on a single `match` case must return values of the same type, `TOutput`.
  - `selections` is an object of properties selected from the input with the [`select` function](#select-patterns).
  - `TInput` might be narrowed to a more precise type using the `pattern`.

### `.when`

```ts
match(...)
  .when(predicate, handler)
```

#### Signature

```ts
function when(
  predicate: (value: TInput) => unknown,
  handler: (value: TInput) => TOutput
): Match<TInput, TOutput>;
```

#### Arguments

- `predicate: (value: TInput) => unknown`
  - **Required**
  - Condition the input must satisfy for the handler to be called.
- `handler: (value: TInput) => TOutput`
  - **Required**
  - Function called when the predicate condition is satisfied.
  - All handlers on a single `match` case must return values of the same type, `TOutput`.

### `.returnType`

```ts
match(...)
  .returnType<string>()
  .with(..., () => "has to be a string")
  .with(..., () => "Oops".length)
  //               ~~~~~~~~~~~~~ ❌ `number` isn't a string!
```

The `.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.

#### Signature

```ts
function returnType<TOutputOverride>(): Match<TInput, TOutputOverride>;
```

#### Type arguments

- `TOutputOverride`
  - The type that your `match` expression will return. All branches must return values assignable to it.

### `.exhaustive`

```ts
match(...)
  .with(...)
  .exhaustive()
```

Runs 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**.

By 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.

It 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:

```ts
match(...)
  .with(...)
  .exhaustive((unexpected: unknown) => {
    throw MyCustomError(unexpected);
  })
```

Or log an error and return a default value:

```ts
match<string, number>(...)
  .with(P.string, (str) => str.length)
  .exhaustive((notAString: unknown) => {
    console.log(`received an unexpected value: ${notAString}`);
    return 0;
  })
```

#### Signature

```ts
function exhaustive(): TOutput;
function exhaustive(handler: (unexpectedValue: unknown) => TOutput): TOutput;
```

#### Example

```ts
type Permission = 'editor' | 'viewer';
type Plan = 'basic' | 'pro';

const fn = (org: Plan, user: Permission) =>
  match([org, user])
    .with(['basic', 'viewer'], () => {})
    .with(['basic', 'editor'], () => {})
    .with(['pro', 'viewer'], () => {})
    // Fails with `NonExhaustiveError<['pro', 'editor']>`
    // because the `['pro', 'editor']` case isn't handled.
    .exhaustive();

const fn2 = (org: Plan, user: Permission) =>
  match([org, user])
    .with(['basic', 'viewer'], () => {})
    .with(['basic', 'editor'], () => {})
    .with(['pro', 'viewer'], () => {})
    .with(['pro', 'editor'], () => {})
    .exhaustive(); // Works!
```

### `.otherwise`

```ts
match(...)
  .with(...)
  .otherwise(defaultHandler)
```

Runs 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.

#### Signature

```ts
function otherwise(defaultHandler: (value: TInput) => TOutput): TOutput;
```

#### Arguments

- `defaultHandler: (value: TInput) => TOutput`
  - **Required**
  - Function called if no pattern matched the input value.
  - Think of it as the `default:` case of `switch` statements.
  - All handlers on a single `match` case must return values of the same type, `TOutput`.

### `.run`

```ts
match(...)
  .with(...)
  .run()
```

returns 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.

#### Signature

```ts
function run(): TOutput;
```

### `.narrow`

```ts
match(...)
  .with(...)
  .narrow()
  .with(...)
```

The `.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.

Note that handled case of top-level union types are excluded by default, without calling `.narrow()`.

#### Signature

```ts
function narrow(): Match<Narrowed<TInput>, TOutput>;
```

#### Example

```ts
type Input = { color: 'red' | 'blue'; size: 'small' | 'large' };

declare const input: Input;

const result = match(input)
  .with({ color: 'red', size: 'small' }, (red) => `Red: ${red.size}`)
  .with({ color: 'blue', size: 'large' }, (red) => `Red: ${red.size}`)
  .narrow() // 👈
  .otherwise((narrowedInput) => {
    // narrowedInput:
    // | { color: 'red'; size: 'large' }
    // | { color: 'blue'; size: 'small' }
  });
```

### `isMatching`

```ts
if (isMatching(pattern, value))  {
  ...
}
```

`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.

With a single argument:

```ts
import { isMatching, P } from 'ts-pattern';

const isBlogPost = isMatching({
  type: 'blogpost',
  title: P.string,
  description: P.string,
});

if (isBlogPost(value)) {
  // value: { type: 'blogpost', title: string, description: string }
}
```

With two arguments:

```ts
const blogPostPattern = {
  type: 'blogpost',
  title: P.string,
  description: P.string,
} as const;

if (isMatching(blogPostPattern, value)) {
  // value: { type: 'blogpost', title: string, description: string }
}
```

#### Signature

```ts
export function isMatching<p extends Pattern<any>>(
  pattern: p
): (value: any) => value is InvertPattern<p>;
export function isMatching<p extends Pattern<any>>(
  pattern: p,
  value: any
): value is InvertPattern<p>;
```

#### Arguments

- `pattern: Pattern<any>`
  - **Required**
  - The pattern a value should match.
- `value?: any`
  - **Optional**
  - if a value is given as second argument, `isMatching` will return a boolean telling us whether the pattern matches the value or not.
  - 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.

## Patterns

A pattern is a description of the expected shape of your input value.

Patterns 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),
[`P.when`](#pwhen-patterns), [`P.select`](#pselect-patterns), ...).

All wildcards and matcher functions can be imported either as `Pattern` or as `P` from the `ts-pattern` module.

```ts
import { match, Pattern } from 'ts-pattern';

const toString = (value: unknown): string =>
  match(value)
    .with(Pattern.string, (str) => str)
    .with(Pattern.number, (num) => num.toFixed(2))
    .with(Pattern.boolean, (bool) => `${bool}`)
    .otherwise(() => 'Unknown');
```

Or

```ts
import { match, P } from 'ts-pattern';

const toString = (value: unknown): string =>
  match(value)
    .with(P.string, (str) => str)
    .with(P.number, (num) => num.toFixed(2))
    .with(P.boolean, (bool) => `${bool}`)
    .otherwise(() => 'Unknown');
```

If 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.

### Literals

Literals are primitive JavaScript values, like `numbers`, `strings`, `booleans`, `bigints`, `symbols`, `null`, `undefined`, or `NaN`.

```ts
import { match } from 'ts-pattern';

const input: unknown = 2;

const output = match(input)
  .with(2, () => 'number: two')
  .with(true, () => 'boolean: true')
  .with('hello', () => 'string: hello')
  .with(undefined, () => 'undefined')
  .with(null, () => 'null')
  .with(NaN, () => 'number: NaN')
  .with(20n, () => 'bigint: 20n')
  .otherwise(() => 'something else');

console.log(output);
// => 'number: two'
```

### Objects

Patterns can be objects containing sub-patterns. An object pattern will match
If and only if the input value **is an object**, contains **all properties** the pattern defines
and each property **matches** the corresponding sub-pattern.

```ts
import { match } from 'ts-pattern';

type Input =
  | { type: 'user'; name: string }
  | { type: 'image'; src: string }
  | { type: 'video'; seconds: number };

let input: Input = { type: 'user', name: 'Gabriel' };

const output = match(input)
  .with({ type: 'image' }, () => 'image')
  .with({ type: 'video', seconds: 10 }, () => 'video of 10 seconds.')
  .with({ type: 'user' }, ({ name }) => `user of name: ${name}`)
  .otherwise(() => 'something else');

console.log(output);
// => 'user of name: Gabriel'
```

### Tuples (arrays)

In TypeScript, [Tuples](https://en.wikipedia.org/wiki/Tuple) are arrays with a fixed
number of elements that can be of different types. You can pattern-match on tuples
using a tuple pattern. A tuple pattern will match if the input value **is an array of the same length**,
and each item matches the corresponding sub-pattern.

```ts
import { match, P } from 'ts-pattern';

type Input =
  | [number, '+', number]
  | [number, '-', number]
  | [number, '*', number]
  | ['-', number];

const input = [3, '*', 4] as Input;

const output = match(input)
  .with([P._, '+', P._], ([x, , y]) => x + y)
  .with([P._, '-', P._], ([x, , y]) => x - y)
  .with([P._, '*', P._], ([x, , y]) => x * y)
  .with(['-', P._], ([, x]) => -x)
  .exhaustive();

console.log(output);
// => 12
```

### Wildcards

#### `P._` wildcard

The `P._` pattern will match any value. You can also use `P.any`, which is an alias to `P._`.

```ts
import { match, P } from 'ts-pattern';

const input = 'hello';

const output = match(input)
  .with(P._, () => 'It will always match')
  // OR
  .with(P.any, () => 'It will always match')
  .otherwise(() => 'This string will never be used');

console.log(output);
// => 'It will always match'
```

#### `P.string` wildcard

The `P.string` pattern will match any value of type `string`.

```ts
import { match, P } from 'ts-pattern';

const input = 'hello';

const output = match(input)
  .with('bonjour', () => 'Won‘t match')
  .with(P.string, () => 'it is a string!')
  .exhaustive();

console.log(output);
// => 'it is a string!'
```

#### `P.number` wildcard

The `P.number` pattern will match any value of type `number`.

```ts
import { match, P } from 'ts-pattern';

const input = 2;

const output = match<number | string>(input)
  .with(P.string, () => 'it is a string!')
  .with(P.number, () => 'it is a number!')
  .exhaustive();

console.log(output);
// => 'it is a number!'
```

#### `P.boolean` wildcard

The `P.boolean` pattern will match any value of type `boolean`.

```ts
import { match, P } from 'ts-pattern';

const input = true;

const output = match<number | string | boolean>(input)
  .with(P.string, () => 'it is a string!')
  .with(P.number, () => 'it is a number!')
  .with(P.boolean, () => 'it is a boolean!')
  .exhaustive();

console.log(output);
// => 'it is a boolean!'
```

#### `P.nullish` wildcard

The `P.nullish` pattern will match any value of type `null` or `undefined`.

Even though `null` and `undefined` can be used as literal patterns, sometimes they appear in a union together
(e.g. `null | undefined | string`) and you may want to treat them as equivalent using `P.nullish`.

```ts
import { match, P } from 'ts-pattern';

const input = null;

const output = match<number | null | undefined>(input)
  .with(P.number, () => 'it is a number!')
  .with(P.nullish, () => 'it is either null or undefined!')
  .exhaustive();

console.log(output);
// => 'it is either null or undefined!'
```

#### `P.nonNullable` wildcard

The `P.nonNullable` pattern will match any value except `null` or `undefined`.

```ts
import { match, P } from 'ts-pattern';

const input = null;

const output = match<number | null | undefined>(input)
  .with(P.nonNullable, () => 'it is a number!')
  .otherwise(() => 'it is either null or undefined!');

console.log(output);
// => 'it is either null or undefined!'
```

#### `P.bigint` wildcard

The `P.bigint` pattern will match any value of type `bigint`.

```ts
import { match, P } from 'ts-pattern';

const input = 20000000n;

const output = match<bigint | null>(input)
  .with(P.bigint, () => 'it is a bigint!')
  .otherwise(() => '?');

console.log(output);
// => 'it is a bigint!'
```

#### `P.symbol` wildcard

The `P.symbol` pattern will match any value of type `symbol`.

```ts
import { match, P } from 'ts-pattern';

const input = Symbol('some symbol');

const output = match<symbol | null>(input)
  .with(P.symbol, () => 'it is a symbol!')
  .otherwise(() => '?');

console.log(output);
// => 'it is a symbol!'
```

### `P.array` patterns

To match on arrays of unknown size, you can use `P.array(subpattern)`.
It takes a sub-pattern, and will match if **all elements** in the input
array match this sub-pattern.

```ts
import { match, P } from 'ts-pattern';

type Input = { title: string; content: string }[];

let input: Input = [
  { title: 'Hello world!', content: 'This is a very interesting content' },
  { title: 'Bonjour!', content: 'This is a very interesting content too' },
];

const output = match(input)
  .with(
    P.array({ title: P.string, content: P.string }),
    (posts) => 'a list of posts!'
  )
  .otherwise(() => 'something else');

console.log(output);
// => 'a list of posts!'
```

### Matching variadic tuples with `P.array`

In 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)`:

```ts
import { match, P } from 'ts-pattern';

type Input = (number | string)[];

declare const input: Input;

const output = match(input)
  // P.array's parameter is optional
  .with([P.string, ...P.array()], (input) => input) // input: [string, ...(number | string)[]]
  .with(['print', ...P.array(P.string)], (input) => input) // input: ['print', ...string[]]
  // you can put patterns on either side of `...P.array()`:
  .with([...P.array(P.string), 'end'], (input) => input) // input: [...string[], 'end']
  .with(['start', ...P.array(P.string), 'end'], (input) => input) // input: ['start', ...string[], 'end']
  .otherwise((input) => input);
```

### `P.record` patterns

To match a `Record<Key, Value>` (an object with consistent key and value types), you can use `P.record(keyPattern, valuePattern)`.
It 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
match these two sub-patterns.

```ts
import { match, P } from 'ts-pattern';

type Input = Record<string, number>;

const input: Input = {
  alice: 100,
  bob: 85,
  charlie: 92,
};

const output = match(input)
  .with(P.record(P.string, P.number), (scores) => `All user scores`)
  .with(P.record(P.string, P.string), (names) => `All user names`)
  .otherwise(() => '');

console.log(output);
// => "All user scores"
```

You can also use `P.record` with a single argument `P.record(valuePattern)`, which assumes string keys:

```ts
const userProfiles = {
  alice: { name: 'Alice', age: 25 },
  bob: { name: 'Bob', age: 30 },
};

const output = match(userProfiles)
  .with(
    P.record({ name: P.string, age: P.number }),
    (profiles) => `User profiles with name and age`
  )
  .otherwise(() => 'Different format');

console.log(output);
// => "User profiles with name and age"
```

When using `P.select` in record patterns, you can extract all keys or all values as arrays:

```ts
const data = { a: 1, b: 2, c: 3 };

const keys = match(data)
  .with(P.record(P.string.select(), P.number), (keys) => keys)
  .otherwise(() => []);

const values = match(data)
  .with(P.record(P.string, P.number.select()), (values) => values)
  .otherwise(() => []);

console.log(keys); // => ['a', 'b', 'c']
console.log(values); // => [1, 2, 3]
```

### `P.set` patterns

To match a Set, you can use `P.set(subpattern)`.
It takes a sub-pattern, and will match if **all elements** inside the set
match this sub-pattern.

```ts
import { match, P } from 'ts-pattern';

type Input = Set<string | number>;

const input: Input = new Set([1, 2, 3]);

const output = match(input)
  .with(P.set(1), (set) => `Set contains only 1`)
  .with(P.set(P.string), (set) => `Set contains only strings`)
  .with(P.set(P.number), (set) => `Set contains only numbers`)
  .otherwise(() => '');

console.log(output);
// => "Set contains only numbers"
```

### `P.map` patterns

To match a Map, you can use `P.map(keyPattern, valuePattern)`.
It takes a subpattern to match against the key, a subpattern to match agains the value, and will match if **all elements** inside this map
match these two sub-patterns.

```ts
import { match, P } from 'ts-pattern';

type Input = Map<string, string | number>;

const input: Input = new Map([
  ['a', 1],
  ['b', 2],
  ['c', 3],
]);

const output = match(input)
  .with(P.map(P.string, P.number), (map) => `map's type is Map<string, number>`)
  .with(P.map(P.string, P.string), (map) => `map's type is Map<string, string>`)
  .with(
    P.map(P.union('a', 'c'), P.number),
    (map) => `map's type is Map<'a' | 'c', number>`
  )
  .otherwise(() => '');

console.log(output);
// => "map's type is Map<string, number>"
```

### `P.when` patterns

`P.when` lets you define your own logic to check if the pattern should match or not.
If the `predicate` function given to when returns a truthy value, then the pattern
will match for this input.

Note that you can narrow down the type of your input by providing a
[Type Guard function](https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards) to `P.when`.

```ts
import { match, P } from 'ts-pattern';

type Input = { score: number };

const output = match<Input>({ score: 10 })
  .with(
    {
      score: P.when((score): score is 5 => score === 5),
    },
    (input) => '😐' // input is inferred as { score: 5 }
  )
  .with({ score: P.when((score) => score < 5) }, () => '😞')
  .otherwise(() => '🙂');

console.log(output);
// => '🙂'
```

### `P.not` patterns

`P.not` lets you match on everything **but** a specific value.
it's a function taking a pattern and returning the opposite pattern.

```ts
import { match, P } from 'ts-pattern';

type Input = boolean | number;

const toNumber = (input: Input) =>
  match(input)
    .with(P.not(P.boolean), (n) => n) // n: number
    .with(true, () => 1)
    .with(false, () => 0)
    .exhaustive();

console.log(toNumber(2));
// => 2
console.log(toNumber(true));
// => 1
```

### `P.select` patterns

`P.select` lets you pick a piece of your input data-structure
and injects it in your handler function.

It's especially useful when pattern matching on deep data structure to
avoid the hassle of destructuring it in the handler function.

Selections can be either named (with `P.select('someName')`) or anonymous (with `P.select()`).

You can have only one anonymous selection by pattern, and the selected value will be directly inject in your handler as first argument:

```ts
import { match, P } from 'ts-pattern';

type Input =
  | { type: 'post'; user: { name: string } }
  | { ... };

const input: Input = { type: 'post', user: { name: 'Gabriel' } }

const output = match(input)
    .with(
      { type: 'post', user: { name: P.select() } },
      username => username // username: string
    )
    .otherwise(() => 'anonymous');

console.log(output);
// => 'Gabriel'
```

If 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.

```ts
import { match, P } from 'ts-pattern';

type Input =
  | { type: 'post'; user: { name: string }, content: string }
  | { ... };

const input: Input = { type: 'post', user: { name: 'Gabriel' }, content: 'Hello!' }

const output = match(input)
    .with(
      { type: 'post', user: { name: P.select('name') }, content: P.select('body') },
      ({ name, body }) => `${name} wrote "${body}"`
    )
    .otherwise(() => '');

console.log(output);
// => 'Gabriel wrote "Hello!"'
```

You can also pass a sub-pattern to `P.select` if you want it to only
select values which match this sub-pattern:

```ts
type User = { age: number; name: string };
type Post = { body: string };
type Input = { author: User; content: Post };

declare const input: Input;

const output = match(input)
  .with(
    {
      author: P.select({ age: P.number.gt(18) }),
    },
    (author) => author // author: User
  )
  .with(
    {
      author: P.select('author', { age: P.number.gt(18) }),
      content: P.select(),
    },
    ({ author, content }) => author // author: User, content: Post
  )
  .otherwise(() => 'anonymous');
```

### `P.optional` patterns

`P.optional(subpattern)` lets you annotate a key in an object pattern as being optional,
but if it is defined it should match a given sub-pattern.

```ts
import { match, P } from 'ts-pattern';

type Input = { key?: string | number };

const output = match(input)
  .with({ key: P.optional(P.string) }, (a) => {
    return a.key; // string | undefined
  })
  .with({ key: P.optional(P.number) }, (a) => {
    return a.key; // number | undefined
  })
  .exhaustive();
```

### `P.instanceOf` patterns

The `P.instanceOf` function lets you build a pattern to check if
a value is an instance of a class:

```ts
import { match, P } from 'ts-pattern';

class A {
  a = 'a';
}
class B {
  b = 'b';
}

type Input = { value: A | B };

const input: Input = { value: new A() };

const output = match(input)
  .with({ value: P.instanceOf(A) }, (a) => {
    return 'instance of A!';
  })
  .with({ value: P.instanceOf(B) }, (b) => {
    return 'instance of B!';
  })
  .exhaustive();

console.log(output);
// => 'instance of A!'
```

### `P.union` patterns

`P.union(...subpatterns)` lets you test several patterns and will match if
one of these patterns do. It's particularly handy when you want to handle
some cases of a union type in the same code branch:

```ts
import { match, P } from 'ts-pattern';

type Input =
  | { type: 'user'; name: string }
  | { type: 'org'; name: string }
  | { type: 'text'; content: string }
  | { type: 'img'; src: string };

declare const input: Input;

const output = match(input)
  .with({ type: P.union('user', 'org') }, (userOrOrg) => {
    // userOrOrg: User | Org
    return userOrOrg.name;
  })
  .otherwise(() => '');
```

### `P.intersection` patterns

`P.intersection(...subpatterns)` lets you ensure that the input matches
**all** sub-patterns passed as parameters.

```ts
class A {
  constructor(public foo: 'bar' | 'baz') {}
}

class B {
  constructor(public str: string) {}
}

type Input = { prop: A | B };

declare const input: Input;

const output = match(input)
  .with(
    { prop: P.intersection(P.instanceOf(A), { foo: 'bar' }) },
    ({ prop }) => prop.foo // prop: A & { foo: 'bar' }
  )
  .with(
    { prop: P.intersection(P.instanceOf(A), { foo: 'baz' }) },
    ({ prop }) => prop.foo // prop: A & { foo: 'baz' }
  )
  .otherwise(() => '');
```

## `P.string` predicates

`P.string` has a number of methods to help you match on specific strings.

### `P.string.startsWith`

`P.string.startsWith(str)` matches strings that start with the provided string.

```ts
const fn = (input: string) =>
  match(input)
    .with(P.string.startsWith('TS'), () => '🎉')
    .otherwise(() => '❌');

console.log(fn('TS-Pattern')); // logs '🎉'
```

### `P.string.endsWith`

`P.string.endsWith(str)` matches strings that end with the provided string.

```ts
const fn = (input: string) =>
  match(input)
    .with(P.string.endsWith('!'), () => '🎉')
    .otherwise(() => '❌');

console.log(fn('Hola!')); // logs '🎉'
```

### `P.string.minLength`

`P.string.minLength(min)` matches strings with at least `min` characters.

```ts
const fn = (input: string) =>
  match(input)
    .with(P.string.minLength(2), () => '🎉')
    .otherwise(() => '❌');

console.log(fn('two')); // logs '🎉'
```

### `P.string.length`

`P.string.length(len)` matches strings with exactly `len` characters.

```ts
const fn = (input: string) =>
  match(input)
    .with(P.string.length(2), () => '🎉')
    .otherwise(() => '❌');

console.log(fn('ok')); // logs '🎉'
```

### `P.string.maxLength`

`P.string.maxLength(max)` matches strings with at most `max` characters.

```ts
const fn = (input: string) =>
  match(input)
    .with(P.string.maxLength(5), () => '🎉')
    .otherwise(() => 'too long');

console.log(fn('is this too long?')); // logs 'too long'
```

### `P.string.includes`

`P.string.includes(str)` matches strings that contain the provided substring.

```ts
const fn = (input: string) =>
  match(input)
    .with(P.string.includes('!'), () => '✅')
    .otherwise(() => '❌');

console.log(fn('Good job! 🎉')); // logs '✅'
```

### `P.string.regex`

`P.string.regex(RegExp)` matches strings if they match the provided regular expression.

```ts
const fn = (input: string) =>
  match(input)
    .with(P.string.regex(/^[a-z]+$/), () => 'single word')
    .otherwise(() => 'other strings');

console.log(fn('gabriel')); // logs 'single word'
```

## `P.number` and `P.bigint` predicates

`P.number` and `P.bigint` have several of methods to help you match on specific numbers and bigints.

### `P.number.between`

`P.number.between(min, max)` matches numbers between `min` and `max`.

```ts
const fn = (input: number) =>
  match(input)
    .with(P.number.between(1, 5), () => '✅')
    .otherwise(() => '❌');

console.log(fn(3), fn(1), fn(5), fn(7)); // logs '✅ ✅ ✅ ❌'
```

### `P.number.lt`

`P.number.lt(max)` matches numbers smaller than `max`.

```ts
const fn = (input: number) =>
  match(input)
    .with(P.number.lt(7), () => '✅')
    .otherwise(() => '❌');

console.log(fn(2), fn(7)); // logs '✅ ❌'
```

### `P.number.gt`

`P.number.gt(min)` matches numbers greater than `min`.

```ts
const fn = (input: number) =>
  match(input)
    .with(P.number.gt(7), () => '✅')
    .otherwise(() => '❌');

console.log(fn(12), fn(7)); // logs '✅ ❌'
```

### `P.number.lte`

`P.number.lte(max)` matches numbers smaller than or equal to `max`.

```ts
const fn = (input: number) =>
  match(input)
    .with(P.number.lte(7), () => '✅')
    .otherwise(() => '❌');

console.log(fn(7), fn(12)); // logs '✅ ❌'
```

### `P.number.gte`

`P.number.gte(min)` matches numbers greater than or equal to `min`.

```ts
const fn = (input: number) =>
  match(input)
    .with(P.number.gte(7), () => '✅')
    .otherwise(() => '❌');

console.log(fn(7), fn(2)); // logs '✅ ❌'
```

### `P.number.int`

`P.number.int()` matches integers.

```ts
const fn = (input: number) =>
  match(input)
    .with(P.number.int(), () => '✅')
    .otherwise(() => '❌');

console.log(fn(12), fn(-3.141592)); // logs '✅ ❌'
```

### `P.number.finite`

`P.number.finite()` matches all numbers except `Infinity` and `-Infinity`.

```ts
const fn = (input: number) =>
  match(input)
    .with(P.number.finite(), () => '✅')
    .otherwise(() => '❌');

console.log(fn(-3.141592), fn(Infinity)); // logs '✅ ❌'
```

### `P.number.positive`

`P.number.positive()` matches positive numbers.

```ts
const fn = (input: number) =>
  match(input)
    .with(P.number.positive(), () => '✅')
    .otherwise(() => '❌');

console.log(fn(7), fn(-3.141592)); // logs '✅ ❌'
```

### `P.number.negative`

`P.number.negative()` matches negative numbers.

```ts
const fn = (input: number) =>
  match(input)
    .with(P.number.negative(), () => '✅')
    .otherwise(() => '❌');

console.log(fn(-3.141592), fn(7)); // logs '✅ ❌'
```

## Types

### `P.infer`

`P.infer<typeof somePattern>` lets you infer a type of value from a type of pattern.

It's particularly useful when validating an API response.

```ts
const postPattern = {
  title: P.string,
  content: P.string,
  stars: P.number.between(1, 5).optional(),
  author: {
    firstName: P.string,
    lastName: P.string.optional(),
    followerCount: P.number,
  },
} as const;

type Post = P.infer<typeof postPattern>;

// posts: Post[]
const posts = await fetch(someUrl)
  .then((res) => res.json())
  .then((res: unknown): Post[] =>
    isMatching({ data: P.array(postPattern) }, res) ? res.data : []
  );
```

Although not strictly necessary, using `as const` after the pattern definition ensures that TS-Pattern infers the most precise types possible.

### `P.narrow`

`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.

```ts
type Input = ['a' | 'b' | 'c', 'a' | 'b' | 'c'];
const Pattern = ['a', P.union('a', 'b')] as const;

type Narrowed = P.narrow<Input, typeof Pattern>;
//     ^? ['a', 'a' | 'b']
```

Note that most of the time, the `match` and `isMatching` functions perform narrowing for you, and you do not need to narrow types yourself.

### `P.Pattern`

`P.Pattern<T>` is the type of all possible pattern for a generic type `T`.

```ts
type User = { name: string; age: number };

const userPattern: Pattern<User> = {
  name: 'Alice',
};
```

### Type inference

TS-Pattern takes advantage the most advanced features of TypeScript to perform type narrowing and accurate exhaustive matching, even when matching on complex data-structures.

Here are some examples of TS-Pattern's type inference features.

#### Type narrowing

When 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.

```ts
type Text = { type: 'text'; data: string };
type Img = { type: 'img'; data: { src: string; alt: string } };
type Video = { type: 'video'; data: { src: string; format: 'mp4' | 'webm' } };
type Content = Text | Img | Video;

const formatContent = (content: Content): string =>
  match(content)
    .with({ type: 'text' }, (text /* : Text */) => '<p>...</p>')
    .with({ type: 'img' }, (img /* : Img */) => '<img ... />')
    .with({ type: 'video' }, (video /* : Video */) => '<video ... />')
    .with(
      { type: 'img' },
      { type: 'video' },
      (video /* : Img | Video */) => 'img or video'
    )
    .with(
      { type: P.union('img', 'video') },
      (video /* : Img | Video */) => 'img or video'
    )
    .exhaustive();
```

When 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.

```ts
const formatContent = (content: Content): string =>
  match(content)
    .with(
      { type: 'text', data: P.select() },
      (content /* : string */) => '<p>...</p>'
    )
    .with(
      { type: 'video', data: { format: P.select() } },
      (format /* : 'mp4' | 'webm' */) => '<video ... />'
    )
    .with(
      { type: P.union('img', 'video'), data: P.select() },
      (data /* : Img['data'] | Video['data'] */) => 'img or video'
    )
    .exhaustive();
```

#### Type guard function

If 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.

```ts
const isString = (x: unknown): x is string => typeof x === 'string';

const isNumber = (x: unknown): x is number => typeof x === 'number';

const fn = (input: { id: number | string }) =>
  match(input)
    .with({ id: P.when(isString) }, (narrowed /* : { id: string } */) => 'yes')
    .with({ id: P.when(isNumber) }, (narrowed /* : { id: number } */) => 'yes')
    .exhaustive();
```

#### Exhaustiveness checking

TS-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.

```ts
type Permission = 'editor' | 'viewer';
type Plan = 'basic' | 'pro';

const fn = (org: Plan, user: Permission): string =>
  match([org, user])
    .with(['basic', 'viewer'], () => {})
    .with(['basic', 'editor'], () => {})
    .with(['pro', 'viewer'], () => {})
    // Fails with `NonExhaustiveError<['pro', 'editor']>`
    // because the `['pro', 'editor']` case isn't handled.
    .exhaustive();
```

## Inspirations

This library has been heavily inspired by this great article by Wim Jongeneel:
[Pattern Matching in TypeScript with Record and Wildcard Patterns](https://medium.com/swlh/pattern-matching-in-typescript-with-record-and-wildcard-patterns-6097dd4e471d).
It made me realize pattern matching could be implemented in userland and we didn't have
to wait for it to be added to the language itself. I'm really grateful for that 🙏


================================================
FILE: benchmarks/always-last-digit.ts
================================================
import { add, complete, cycle, suite } from 'benny';
import { match } from '../src';

type Digit = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;

const testExhaustive = (digit: Digit) => {
  return match(digit)
    .with(0, () => 'zero')
    .with(1, () => 'one')
    .with(2, () => 'two')
    .with(3, () => 'three')
    .with(4, () => 'four')
    .with(5, () => 'five')
    .with(6, () => 'six')
    .with(7, () => 'seven')
    .with(8, () => 'eight')
    .with(9, () => 'nine')
    .exhaustive();
};

const testOtherwise = (digit: Digit) => {
  return match(digit)
    .with(0, () => 'zero')
    .with(1, () => 'one')
    .with(2, () => 'two')
    .with(3, () => 'three')
    .with(4, () => 'four')
    .with(5, () => 'five')
    .with(6, () => 'six')
    .with(7, () => 'seven')
    .with(8, () => 'eight')
    .with(9, () => 'nine')
    .otherwise(() => '');
};

const testIfElse = (digit: Digit) => {
  if (digit === 0) {
    return 'zero';
  } else if (digit === 1) {
    return 'one';
  } else if (digit === 2) {
    return 'two';
  } else if (digit === 3) {
    return 'three';
  } else if (digit === 4) {
    return 'four';
  } else if (digit === 5) {
    return 'five';
  } else if (digit === 6) {
    return 'six';
  } else if (digit === 7) {
    return 'seven';
  } else if (digit === 8) {
    return 'eight';
  } else if (digit === 9) {
    return 'nine';
  } else {
    return '';
  }
};

const testSwitch = (digit: Digit) => {
  switch (digit) {
    case 0:
      return 'zero';
    case 1:
      return 'one';
    case 2:
      return 'two';
    case 3:
      return 'three';
    case 4:
      return 'four';
    case 5:
      return 'five';
    case 6:
      return 'six';
    case 7:
      return 'seven';
    case 8:
      return 'eight';
    case 9:
      return 'nine';
    default:
      return '';
  }
};

const testTernary = (digit: Digit) => {
  return digit === 0
    ? 'zero'
    : digit === 1
    ? 'one'
    : digit === 2
    ? 'two'
    : digit === 3
    ? 'three'
    : digit === 4
    ? 'four'
    : digit === 5
    ? 'five'
    : digit === 6
    ? 'six'
    : digit === 7
    ? 'seven'
    : digit === 8
    ? 'eight'
    : digit === 9
    ? 'nine'
    : '';
};

suite(
  'ts-pattern-benchmark',
  add('.exhaustive()', () => testExhaustive(9)),
  add('.otherwise()', () => testOtherwise(9)),
  add('if/else', () => testIfElse(9)),
  add('switch', () => testSwitch(9)),
  add('ternary', () => testTernary(9)),
  cycle(),
  complete()
);


================================================
FILE: benchmarks/nested-objects.ts
================================================
import { add, complete, cycle, suite } from 'benny';
import { P, match } from '../src';

const testExhaustive = (input: unknown) => {
  return match(input)
    .with({ type: 'a', value: { x: P.number, y: P.number } }, () => '1')
    .with({ type: 'b', value: [1, ...P.array(P.number)] }, () => '2')
    .with({ type: 'c', name: P.string, age: P.number }, () => '3')
    .otherwise(() => '4');
};

const testIfElse = (input: unknown) => {
  if (
    input &&
    typeof input === 'object' &&
    'type' in input &&
    input.type === 'a' &&
    'value' in input &&
    input.value &&
    typeof input.value === 'object' &&
    'x' in input.value &&
    typeof input.value.x === 'number' &&
    'y' in input.value &&
    typeof input.value.y === 'number'
  ) {
    return '1';
  } else if (
    input &&
    typeof input === 'object' &&
    'type' in input &&
    input.type === 'b' &&
    'value' in input &&
    Array.isArray(input.value) &&
    input.value[0] === 1 &&
    input.value.slice(1).every((x) => typeof x === 'number')
  ) {
    return '2';
  } else if (
    input &&
    typeof input === 'object' &&
    'type' in input &&
    input.type === 'c' &&
    'name' in input &&
    typeof input.name === 'string' &&
    'age' in input &&
    typeof input.age === 'number'
  ) {
    return '3';
  } else {
    return '4';
  }
};

const rand = () => {
  const map = {
    0: { type: 'a' as const, value: { x: Math.random(), y: Math.random() } },
    1: {
      type: 'b' as const,
      value: Math.random() > 0.5 ? [1, 2, 3, 4] : ['hello'],
    },
    2: { type: 'c' as const, age: Math.random(), name: 'acdfl' },
  };

  return map[Math.floor(Math.random() * 3) as 0 | 1 | 2];
};

suite(
  'ts-pattern-benchmark',
  add('.exhaustive()', () => testExhaustive(rand())),
  add('if/else', () => testIfElse(rand())),
  cycle(),
  complete()
);


================================================
FILE: benchmarks/package.json
================================================
{
  "name": "ts-pattern-benchmarks",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "npm run always-last-digit && npm run random-digit && npm run nested-objects",
    "always-last-digit": "bun run ./always-last-digit.ts",
    "random-digit": "bun run ./random-digit.ts",
    "nested-objects": "bun run ./nested-objects.ts"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "benny": "^3.7.1",
    "bun": "^1.1.30",
    "ts-pattern": "^5.0.5"
  }
}

================================================
FILE: benchmarks/random-digit.ts
================================================
import { add, complete, cycle, suite } from 'benny';
import { match } from '../src';

type Digit = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;

const testExhaustive = (digit: Digit) => {
  return match(digit)
    .with(0, () => 'zero')
    .with(1, () => 'one')
    .with(2, () => 'two')
    .with(3, () => 'three')
    .with(4, () => 'four')
    .with(5, () => 'five')
    .with(6, () => 'six')
    .with(7, () => 'seven')
    .with(8, () => 'eight')
    .with(9, () => 'nine')
    .exhaustive();
};

const testOtherwise = (digit: Digit) => {
  return match(digit)
    .with(0, () => 'zero')
    .with(1, () => 'one')
    .with(2, () => 'two')
    .with(3, () => 'three')
    .with(4, () => 'four')
    .with(5, () => 'five')
    .with(6, () => 'six')
    .with(7, () => 'seven')
    .with(8, () => 'eight')
    .with(9, () => 'nine')
    .otherwise(() => '');
};

const testIfElse = (digit: Digit) => {
  if (digit === 0) {
    return 'zero';
  } else if (digit === 1) {
    return 'one';
  } else if (digit === 2) {
    return 'two';
  } else if (digit === 3) {
    return 'three';
  } else if (digit === 4) {
    return 'four';
  } else if (digit === 5) {
    return 'five';
  } else if (digit === 6) {
    return 'six';
  } else if (digit === 7) {
    return 'seven';
  } else if (digit === 8) {
    return 'eight';
  } else if (digit === 9) {
    return 'nine';
  } else {
    return '';
  }
};

const testSwitch = (digit: Digit) => {
  switch (digit) {
    case 0:
      return 'zero';
    case 1:
      return 'one';
    case 2:
      return 'two';
    case 3:
      return 'three';
    case 4:
      return 'four';
    case 5:
      return 'five';
    case 6:
      return 'six';
    case 7:
      return 'seven';
    case 8:
      return 'eight';
    case 9:
      return 'nine';
    default:
      return '';
  }
};

const testTernary = (digit: Digit) => {
  return digit === 0
    ? 'zero'
    : digit === 1
    ? 'one'
    : digit === 2
    ? 'two'
    : digit === 3
    ? 'three'
    : digit === 4
    ? 'four'
    : digit === 5
    ? 'five'
    : digit === 6
    ? 'six'
    : digit === 7
    ? 'seven'
    : digit === 8
    ? 'eight'
    : digit === 9
    ? 'nine'
    : '';
};

const rand = () => Math.floor(Math.random() * 10) as Digit;

suite(
  'ts-pattern-benchmark',
  add('.exhaustive()', () => testExhaustive(rand())),
  add('.otherwise()', () => testOtherwise(rand())),
  add('if/else', () => testIfElse(rand())),
  add('switch', () => testSwitch(rand())),
  add('ternary', () => testTernary(rand())),
  cycle(),
  complete()
);


================================================
FILE: docs/roadmap.md
================================================
### Roadmap

- [ ] `P.ExactPattern<Type>` to infer the exact pattern you must write to fully cover all possible properties of `Type`.
- [ ] Allow calling `isMatching` with a type parameter to restrain the pattern type: `isMatching<Type>(pattern)`.
- [ ] better variant attempt.
- [ ] `.narrow()` as an opt-in option to narrow the input type after a `.with`
- [ ] `P.array.includes(x)`
- [ ] `P.record({Pkey}, {Pvalue})`
- [ ] `P.record`
- [ ] `P.unknown` alias to any.
- [x] `P.nonNullable`
- [x] chainable methods
  - [x] string
    - [x] `P.string.includes('str')`
    - [x] `P.string.startsWith('str')`
    - [x] `P.string.endsWith('str')`
    - [x] `P.string.regex('[a-z]+')`
  - [x] numbers
    - [x] `P.number.between(1, 10)`
    - [x] `P.number.lt(12)`
    - [x] `P.number.gt(12)`
    - [x] `P.number.gte(12)`
    - [x] `P.number.lte(12)`
    - [x] `P.number.int(12)`
    - [x] `P.number.finite`
    - [x] `P.number.positive`
    - [x] `P.number.negative`
  - [x] all
    - [x] `P.number.optional`
    - [x] `P.string.optional`
    - [x] `P.number.select()`
    - [x] `P.string.select()`
    - [x] `P.number.optional.select()`
    - [x] `P.string.optional.select()`
- [x] Add a custom matcher protocol data structures could implement to make them matchable.
- [x] (Maybe) add an iterator protocol to `P.array` to be usable as a variadic tuple pattern. Example of using `P.array`:

```ts
const reverse = <T>(xs: T[]): T[] => {
  return match<T[], T[]>(xs)
    .with([P.any, ...P.array()], ([x, ...xs]) => [...reverse(xs), x])
    .otherwise(() => []);
};

match(xs)
  .with([P.any, ...P.array()], (xs: [unknown, ...unknown[]]) => [])
  .with([42, ...P.array(P.number), '!'], (xs: [42, ...number[], '!']) => [])
  .with(
    [...P.array(P.number), ...P.array(P.string)],
    (xs: [...number[], ...string[]]) => []
  )
  .otherwise(() => []);
```

- [x] update `select()` and `select('name')` to accept a pattern the selected value should match.
- [x] add a `union(...patterns)` pattern.
- [x] When not provided, maybe compute the output type from all branches
- [x] maybe add a lightweight `select` API for single values
- [x] add support matching against several patterns in a single `.with()` clause.
- [x] Find a way to enforce exhaustive pattern matching
- [x] Several pattern/when clauses if necessary, with refined type inference from one to the other
- [x] Find a way to make the full type inference work
- [x] Add an operator to select a part of the data structure
- [x] Add `not(value)` in patterns.
- [x] Narrow down to type of value in `when` if the predicate is a type guard.


================================================
FILE: docs/v3-to-v4-migration-guide.md
================================================
# TS-Pattern v3 to v4 Migration Guide

## Breaking changes

### Imports

type-specific wildcard patterns have moved from `__.<pattern>` to a new `Pattern` qualified module, also exported as `P` by ts-pattern.

```diff
- import { match, __ } from 'ts-pattern';
+ import { match, Pattern } from 'ts-pattern';


const toString = (value: string | number) =>
  match(value)
-   .with(__.string, (v) => v)
-   .with(__.number, (v) => `${v}`)
+   .with(Pattern.string, (v) => v)
+   .with(Pattern.number, (v) => `${v}`)
    .exhaustive();
```

or

```diff
- import { match, __ } from 'ts-pattern';
+ import { match, P } from 'ts-pattern';


const toString = (value: string | number) =>
  match(value)
-   .with(__.string, (v) => v)
-   .with(__.number, (v) => `${v}`)
+   .with(P.string, (v) => v)
+   .with(P.number, (v) => `${v}`)
    .exhaustive();
```

#### `__`

The top level `__` export was moved to `P._` and `P.any`:

```diff
- import { match, __ } from 'ts-pattern';
+ import { match, P } from 'ts-pattern';


const toString = (value: string | number) =>
  match(value)
-   .with(__, (v) => `${v}`)
+   .with(P._, (v) => `${v}`)
    // OR
+   .with(P.any, (v) => `${v}`)
    .exhaustive();
```

#### `select()`, `not()`, `when()`

Function to create patterns have been moved to the `P` module.

```diff
- import { match, select, not, when } from 'ts-pattern';
+ import { match, P } from 'ts-pattern';


const toString = (value: number) =>
  match(value)
-   .with({ prop: select() }, (v) => `${v}`)
+   .with({ prop: P.select() }, (v) => `${v}`)

-   .with({ prop: not(10) }, (v) => `${v}`)
+   .with({ prop: P.not(10) }, (v) => `${v}`)

-   .with({ prop: when((x) => x < 5) }, (v) => `${v}`)
+   .with({ prop: P.when((x) => x < 5) }, (v) => `${v}`)
    .exhaustive();
```

#### `Pattern` type

the `Pattern` type which used to be exported at the toplevel is now accessible at `P.Pattern`.

```diff
- import { match, Pattern } from 'ts-pattern';
+ import { match, P } from 'ts-pattern';

- const pattern: Pattern<number> = P.when(x => x > 2);
+ const pattern: P.Pattern<number> = P.when(x => x > 2);
```

### list patterns

The syntax for matching on a list of elements with an unknown length has changed from `[subpattern]` to `P.array(subpattern)`.

Example:

```diff
- import { match, __ } from 'ts-pattern';
+ import { match, P } from 'ts-pattern';


const parseUsers = (response: unknown) =>
  match(response)
-   .with({ data: [{ name: __.string }] }, (users) => users)
+   .with({ data: P.array({ name: P.string }) }, (users) => users)
    .otherwise(() => []);
```

Now `[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).

### NaN

The `__.NaN` pattern has been replaced by simply using the NaN value in the pattern:

```diff
match<number>(NaN)
-   .with(__.NaN, () => "this is not a number")
+   .with(NaN, () => "this is not a number")
    .otherwise((n) => n);
```

## New features

Here is the list of all new features which have been added in TS-Pattern v4.

### Arrays and unary tuples

#### `P.array(pattern)`

To match an array of elements, you can now use `P.array`:

```ts
import { match, P } from 'ts-pattern';

const responsePattern = {
  data: P.array({
    id: P.string,
    post: P.array({
      title: P.string,
      content: P.string,
    }),
  }),
};

fetchSomething().then((value: unknown) =>
  match(value)
    .with(responsePattern, (value) => {
      // value: { data: { id: string, post: { title: string, content: string }[] }[] }
      return value;
    })
    .otherwise(() => {
      throw new Error('unexpected response');
    })
);
```

### Optional object properties

#### `P.optional(pattern)`

If you want one of the keys of your pattern to be optional, you can now use `P.optional(subpattern)`.

If you `P.select()` something in an optional pattern, it's type will be infered as `T | undefined`.

```ts
import { match, P } from 'ts-pattern';

const doSomethingWithUser = (user: User | Org) =>
  match(user)
    .with(
      {
        type: 'user',
        detail: {
          bio: P.optional(P.string),
          socialLinks: P.optional({
            twitter: P.select(),
          }),
        },
      },
      (twitterLink, value) => {
        // twitterLink: string | undefined
        /**
         *  value.detail: {
         *      bio?: string,
         *      socialLinks?: {
         *          twitter: string
         *      }
         *  }
         **/
      }
    )
    .otherwise(() => {
      throw new Error('unexpected response');
    });
```

### Union & intersection patterns

`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`).

#### `P.union(...patterns)`

```ts
type Input =
  | { type: 'a'; value: string }
  | { type: 'b'; value: number }
  | {
      type: 'c';
      value:
        | { type: 'd'; value: boolean }
        | { type: 'e'; value: string[] }
        | { type: 'f'; value: number[] };
    };

const f = (input: Input) =>
  match(input)
    .with(
      { type: P.union('a', 'b') },
      // x: { type: 'a'; value: string } | { type: 'b'; value: number }
      (x) => 'branch 1'
    )
    .with(
      // P.union can take any subpattern:
      {
        type: 'c',
        value: { value: P.union(P.boolean, P.array(P.string)) },
      },
      (x) => 'branch 2' // x.value.value: boolean | string[]
    )
    .with({ type: 'c', value: { type: 'f' } }, () => 'branch 3')
    .exhaustive();
```

#### `P.intersection(...patterns)`

```ts
class A {
  constructor(public foo: 'bar' | 'baz') {}
}

class B {
  constructor(public str: string) {}
}

const f = (input: { prop: A | B }) =>
  match(input)
    .with(
      { prop: P.intersection(P.instanceOf(A), { foo: 'bar' }) },
      // prop: A & { foo: 'bar' }
      ({ prop }) => 'branch 1'
    )
    .with(
      { prop: P.intersection(P.instanceOf(A), { foo: 'baz' }) },
      // prop: A & { foo: 'baz' }
      ({ prop }) => 'branch 2'
    )
    .with(
      { prop: P.instanceOf(B) },
      // prop: B
      ({ prop }) => 'branch 3'
    )
    .exhaustive();
```

### Select with sub pattern

`P.select()` now can take a subpattern and match only what the subpattern matches:

```ts
type Img = { type: 'img'; src: string };
type Text = { type: 'text'; content: string; length: number };
type User = { type: 'user'; username: string };
type Org = { type: 'org'; orgId: number };

const post = (input: { author: User | Org; content: Text | Img }) =>
  match(input)
    .with(
      { author: P.select({ type: 'user' }) },
      // user: User
      (user) => {}
    )
    .with(
      {
        // This also works with named selections
        author: P.select('org', { type: 'org' }),
        content: P.select('text', { type: 'text' }),
      },
      // org: Org, text: Text
      ({ org, text }) => {}
    )
    .otherwise(() => {
      // ...
    });
```

### Infer the matching types from a pattern

#### `P.infer<typeof pattern>`

TS-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.

One 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 :)

```ts
const postPattern = {
  title: P.string,
  description: P.optional(P.string),
  content: P.string,
  likeCount: P.number,
};

type Post = P.infer<typeof postPattern>;
// Post: { title: string, description?: string, content: string, likeCount: number }

const userPattern = {
  name: P.string,
  postCount: P.number,
  bio: P.optional(P.string),
  posts: P.optional(P.array(postPattern)),
};

type User = P.infer<typeof userPattern>;
// User: { name: string, postCount: number, bio?: string, posts?: Post[]  }

const isUserList = isMatching(P.array(userPattern));

const res = await fetchUsers();

if (isUserList(res)) {
  // res: User
}
```

### New type specific wildcards

#### `P.symbol`

`P.symbol` is a wildcard pattern matching any **symbol**.

```ts
match(Symbol('Hello'))
  .with(P.symbol, () => 'this is a symbol!')
  .exhaustive();
```

#### `P.bigint`

`P.bigint` is a wildcard pattern matching any **bigint**.

```ts
match(200n)
  .with(P.bigint, () => 'this is a bigint!')
  .exhaustive();
```


================================================
FILE: docs/v4-to-v5-migration-guide.md
================================================
# TS-Pattern v4 to v5 Migration Guide

This file contains all breaking changes and new features between the version 4 and 5 of TS-Pattern.

# Breaking changes

## TypeScript v5

Because 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+!

## `.with` is now evaluated eagerly

In 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:

```ts
// TS-Pattern v4
type Input = { type: 'ok'; value: number } | { type: 'error'; error: Error };

// We don't call `.exhaustive`, so handlers don't run.
function someFunction(input: Input) {
  match(input)
    .with({ type: 'ok' }, ({ value }) => {
      console.log(value);
    })
    .with({ type: 'error' }, ({ error }) => {
      throw error;
    });
}

someFunction({ type: 'ok', value: 42 }); // nothing happens
```

In **TS-Pattern v5**, however, the library will execute the matching handler as soon as it finds it:

```ts
// TS-Pattern v5
someFunction({ type: 'ok', value: 42 }); // logs "42" to the console!
```

Handlers 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`.

## Matching on Map and Sets

Matching `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:

```diff
- import { match } from 'ts-pattern';
+ import { match, P } from 'ts-pattern';


const someFunction = (value: Set<number> | Map<string, number>) =>
  match(value)
-   .with(new Set([P.number]), (set) => `a set of numbers`)
-   .with(new Map([['key', P.number]]), (map) => `map.get('key') is a number`)
+   .with(P.set(P.number), (set) => `a set of numbers`)
+   .with(P.map('key', P.number), (map) => `map.get('key') is a number`)
    .otherwise(() => null);
```

- The subpattern we provide in `P.set(subpattern)` should match all values in the Set.
- The key and value subpatterns we provide in `P.map(keyPattern, subpattern)` should match all keys and values in the Map.

# New features

## chainable methods

TS-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`.

Since a few examples is worth a thousand words, here are a few ways you can use chainable methods:

### P.number methods

```ts
const example = (position: { x: number; y: number }) =>
  match(position)
    .with({ x: P.number.gte(100) }, (value) => '🎮')
    .with({ x: P.number.between(0, 100) }, (value) => '🎮')
    .with(
      {
        x: P.number.positive().int(),
        y: P.number.positive().int(),
      },
      (value) => '🎮'
    )
    .otherwise(() => 'x or y is negative');
```

Here is the full list of number methods:

- `P.number.between(min, max)`: matches numbers between `min` and `max`.
- `P.number.lt(max)`: matches numbers smaller than `max`.
- `P.number.gt(min)`: matches numbers greater than `min`.
- `P.number.lte(max)`: matches numbers smaller than or equal to `max`.
- `P.number.gte(min)`: matches numbers greater than or equal to `min`.
- `P.number.int()`: matches integers.
- `P.number.finite()`: matches all numbers except `Infinity` and `-Infinity`
- `P.number.positive()`: matches positive numbers.
- `P.number.negative()`: matches negative numbers.

### P.string methods

```ts
const example = (query: string) =>
  match(query)
    .with(P.string.startsWith('SELECT'), (query) => `selection`)
    .with(P.string.endsWith('FROM user'), (query) => `👯‍♂️`)
    .with(P.string.includes('*'), () => 'contains a star')
    // Methods can be chained:
    .with(P.string.startsWith('SET').includes('*'), (query) => `🤯`)
    .exhaustive();
```

Here is the full list of string methods:

- `P.string.startsWith(str)`: matches strings that start with `str`.
- `P.string.endsWith(str)`: matches strings that end with `str`.
- `P.string.minLength(min)`: matches strings with at least `min` characters.
- `P.string.maxLength(max)`: matches strings with at most `max` characters.
- `P.string.includes(str)`: matches strings that contain `str`.
- `P.string.regex(RegExp)`: matches strings if they match this regular expression.

### Global methods

Some methods are available for all primitive type patterns:

- `P.{..}.optional()`: matches even if this property isn't present on the input object.
- `P.{..}.select()`: injects the matched value into the handler function.
- `P.{..}.and(pattern)`: matches if the current pattern **and** the provided pattern match.
- `P.{..}.or(pattern)`: matches if either the current pattern **or** the provided pattern match.

```ts
const example = (value: unknown) =>
  match(value)
    .with(
      {
        username: P.string,
        displayName: P.string.optional(),
      },
      () => `{ username:string, displayName?: string }`
    )
    .with(
      {
        title: P.string,
        author: { username: P.string.select() },
      },
      (username) => `author.username is ${username}`
    )
    .with(
      P.instanceOf(Error).and({ source: P.string }),
      () => `Error & { source: string }`
    )
    .with(P.string.or(P.number), () => `string | number`)
    .otherwise(() => null);
```

## Variadic tuple patterns

With TS-Pattern, you are now able to create array (or more accurately tuple) pattern with a variable number of elements:

```ts
const example = (value: unknown) =>
  match(value)
    .with(
      // non-empty list of strings
      [P.string, ...P.array(P.string)],
      (value) => `value: [string, ...string[]]`
    )
    .otherwise(() => null);
```

Array 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:

```ts
const example = (value: unknown) =>
  match(value)
    .with(
      [P.string, P.string, P.string, ...P.array(P.string)],
      (value) => `value: [string, string, string, ...string[]]`
    )
    .with(
      [P.string, P.string, ...P.array(P.string)],
      (value) => `value: [string, string, ...string[]]`
    )
    .with([], (value) => `value: []`)
    .otherwise(() => null);
```

Fixed-index patterns can also be set **after** the `...P.array` variadic, or on both sides!

```ts
const example = (value: unknown) =>
  match(value)
    .with(
      [...P.array(P.number), P.string, P.number],
      (value) => `value: [...number[], string, number]`
    )
    .with(
      [P.boolean, ...P.array(P.string), P.number, P.symbol],
      (value) => `value: [boolean, ...string[], number, symbol]`
    )
    .otherwise(() => null);
```

Lastly, argument of `P.array` is now optional, and will default to `P._`, which matches anything:

```ts
const example = (value: unknown) =>
  match(value)
    //                         👇
    .with([P.string, ...P.array()], (value) => `value: [string, ...unknown[]]`)
    .otherwise(() => null);
```

## `.returnType`

In 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`:

```ts
// TS-Pattern v4
match<
  { isAdmin: boolean; plan: 'free' | 'paid' }, // input type
  number // return type
>({ isAdmin, plan })
  .with({ isAdmin: true }, () => 123)
  .with({ plan: 'free' }, () => 'Oops!');
//                              ~~~~~~ ❌ not a number.
```

the main drawback is that you need to set the **_input type_** explicitly **_too_**, even though TypeScript should be able to infer it.

In TS-Pattern v5, you can use the `.returnType<Type>()` method to only set the return type:

```ts
match({ isAdmin, plan })
  .returnType<number>() // 👈 new
  .with({ isAdmin: true }, () => 123)
  .with({ plan: 'free' }, () => 'Oops!');
//                              ~~~~~~ ❌ not a number.
```


================================================
FILE: examples/gif-fetcher/package.json
================================================
{
  "name": "ts-pattern-v4-gif-search-demo",
  "version": "1.0.0",
  "description": "",
  "keywords": [],
  "main": "src/index.tsx",
  "dependencies": {
    "lodash": "^4.17.21",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "ts-pattern": "^5.5.0"
  },
  "devDependencies": {
    "@types/lodash": "^4.17.0",
    "@types/react": "^18.2.74",
    "@types/react-dom": "^18.2.24",
    "react-scripts": "^5.0.1",
    "typescript": "^5.4.4"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  }
}

================================================
FILE: examples/gif-fetcher/public/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>TS-Pattern GIF Search Demo</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>


================================================
FILE: examples/gif-fetcher/src/App.tsx
================================================
import { searchGif } from './searchGif';
import { throttle } from 'lodash';
import * as React from 'react';
import './styles.css';

import { match } from 'ts-pattern';

/**
 * The shape of our application state.
 */
type State = {
  query: string;
  data:
    | { status: 'idle' }
    | { status: 'loading' }
    | { status: 'success'; gifUrls: string[] }
    | { status: 'error'; error: Error };
};

/**
 * The union of all events our application
 * can handle.
 */
type Event =
  | { type: 'search'; query: string }
  | { type: 'success'; query: string; gifUrls: string[] }
  | { type: 'error'; query: string; error: Error }
  | { type: 'cancel' };

/**
 * Initial state of our GIF fetcher app
 */
const initState: State = {
  query: '',
  data: { status: 'idle' },
};

/**
 * All state transitions happen in this
 * reducer function
 */
const reducer = (state: State, event: Event): State =>
  match<Event, State>(event)
    .with({ type: 'search' }, ({ query }) => ({
      query,
      data: {
        status: 'loading',
      },
    }))

    .with({ type: 'cancel' }, () => ({
      ...state,
      data: { status: 'idle' },
    }))

    // only transition to success if `event.query`
    // matches `state.query`
    .with({ type: 'success', query: state.query }, ({ gifUrls }) => ({
      ...state,
      data: {
        status: 'success',
        gifUrls,
      },
    }))

    // only transition to error if `event.query`
    // matches `state.query`
    .with({ type: 'error', query: state.query }, ({ error }) => ({
      ...state,
      data: { status: 'error', error },
    }))

    .otherwise(() => state);

export default function App() {
  const [state, dispatch] = React.useReducer(reducer, initState);

  React.useEffect(() => {
    if (state.query) {
      searchGif(state.query)
        .then((urls) =>
          dispatch({
            type: 'success',
            gifUrls: urls,
            query: state.query,
          })
        )
        .catch((error) =>
          dispatch({
            type: 'error',
            error,
            query: state.query,
          })
        );
    } else {
      dispatch({ type: 'cancel' });
    }
  }, [state.query]);

  const onSearch = React.useCallback(
    throttle(
      (query: string) =>
        dispatch({
          type: 'search',
          query,
        }),
      100
    ),
    []
  );

  return (
    <div className="App">
      <input
        placeholder="Search a GIF"
        onChange={(e) => onSearch(e.target.value)}
      />
      <div>
        {match(state.data)
          .with({ status: 'idle' }, () => (
            <>
              <h1>Idle</h1>
              <p>Nothing is happening at the moment</p>
            </>
          ))
          .with({ status: 'loading' }, () => (
            <>
              <h1>Loading...</h1>
            </>
          ))
          .with({ status: 'success', gifUrls: [] }, () => (
            <>
              <h1>No results!</h1>
            </>
          ))
          .with({ status: 'success' }, ({ gifUrls }) => (
            <>
              <h1>Fetch success!</h1>
              <div className="img-grid">
                {gifUrls.map((url) => (
                  <img key={url} src={url} alt="gif" />
                ))}
              </div>
            </>
          ))
          .with({ status: 'error' }, ({ error }) => (
            <>
              <h1>Fetch error!</h1>
              <p>{error.message}</p>
            </>
          ))
          .exhaustive()}
      </div>
    </div>
  );
}


================================================
FILE: examples/gif-fetcher/src/constants.ts
================================================
export const API_KEY = 'xxxxxxxxxxxxxxxx';


================================================
FILE: examples/gif-fetcher/src/index.tsx
================================================
import * as React from 'react';
import { render } from 'react-dom';

import App from './App';

const rootElement = document.getElementById('root');
render(<App />, rootElement);


================================================
FILE: examples/gif-fetcher/src/searchGif.ts
================================================
import { isMatching, P } from 'ts-pattern';
import { API_KEY } from './constants';

const delay = (ms: number) => new Promise((res) => setTimeout(res, ms));

export function searchGif(query: string) {
  return fetch(
    `https://api.giphy.com/v1/gifs/search?api_key=${API_KEY}&q=${query}&limit=25&offset=0&rating=g&lang=en`
  )
    .then((res) => res.json())
    .then(async (res) => {
      await delay(500);
      return res;
    })
    .then((res: unknown) => {
      if (
        isMatching(
          {
            data: P.array({
              images: {
                fixed_height: {
                  url: P.string,
                },
              },
            }),
          },
          res
        )
      ) {
        // Note how `isMatching` narrows the type of `res`:
        return res.data.map(({ images }) => images.fixed_height.url);
      } else {
        throw new Error('Oh, no! The HTTP request failed.');
      }
    });
}


================================================
FILE: examples/gif-fetcher/src/styles.css
================================================
body {
  margin: 0;
}

* {
  box-sizing: border-box;
}

.App {
  margin: 10px;
  font-family: sans-serif;
  text-align: center;
}

input {
  display: block;
  padding: 10px 15px;
  width: 100%;
}

img {
  max-width: 100%;
}

.img-grid {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
}

.img-grid > *:not(:first-child) {
  padding-top: 10px;
}

.img-grid > *:not(:first-child) {
  padding-left: 10px;
}


================================================
FILE: examples/gif-fetcher/tsconfig.json
================================================
{
  "compilerOptions": {
    "esModuleInterop": true,
    "skipLibCheck": true,
    "target": "es2022",
    "allowJs": true,
    "moduleResolution": "Bundler",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "module": "ESNext",
    "noEmit": true,
    "jsx": "react",
    "lib": ["es2022", "dom", "dom.iterable"]
  }
}


================================================
FILE: examples/one-file-demo/one-file-demo.ts
================================================
import { isMatching, match, P } from 'ts-pattern';

/**
 * ### One file TS-Pattern demo.
 *
 * This will demonstrate:
 * - How to use pattern matching and wildcards
 * - How to extract a value from the input Data Structure using `P.select`
 * - How to match several cases using `P.union`
 * - How to leverage exhaustiveness checking to make sure every case is handled
 * - How to pattern match on several values at once using tuples
 * - How to validate an unknown API response using `isMatching` and patterns like
 *   `P.array`, `P.optional`, etc.
 */

/**************************************************
 * Use case 1: handling discriminated union types *
 **************************************************/

type Response =
  | { type: 'video'; data: { format: 'mp4' | 'webm'; src: string } }
  | { type: 'image'; data: { extension: 'gif' | 'jpg' | 'png'; src: string } }
  | { type: 'text'; data: string; tags: { name: string; id: number }[] };

const example1 = (input: Response): string =>
  match(input)
    // 1. Basic pattern with inference with a wildcard
    .with({ type: 'video', data: { format: 'mp4' } }, (video) => video.data.src)
    // 2. using select
    .with(
      { type: 'image', data: { extension: 'gif', src: P.select() } },
      (src) => `<img src=${src} alt="This is a gif!" />`
    )
    // 3. using P.union
    .with(
      {
        type: 'image',
        data: { extension: P.union('jpg', 'png'), src: P.select() },
      },
      (src) => `<img src=${src} alt="This is a jpg or a png!" />`
    )
    // 4. selecting all tag names with P.array and P.select
    .with(
      { type: 'text', tags: P.array({ name: P.select() }) },
      (tagNames) => `text with tags: ${tagNames.join(', ')}`
    )
    // 5. basic exhaustiveness checking
    // ⚠️ doesn't type-check!
    // @ts-expect-error: { type: 'video', data: { format: 'webm' } } isn't covered
    .exhaustive();

/**************************************
 * Use case 2: multi params branching *
 **************************************/

type UserType = 'editor' | 'viewer';
// Uncomment 'enterprise' to see exhaustive checking in action
type OrgPlan = 'basic' | 'pro' | 'premium'; // | 'enterprise';

const example2 = (org: OrgPlan, user: UserType) =>
  // 1. Checking several enums with tuples
  match([org, user])
    .with(['basic', P._], () => `Please upgrade to unlock this feature!`)
    // 2. `.with()` can take several patterns. It will match if one of them do.
    .with(
      ['pro', 'viewer'],
      ['premium', 'viewer'],
      () => `Your account doesn't have permissions to use this feature`
    )
    .with(['pro', 'editor'], () => `Hello!`)
    .with(['premium', 'editor'], () => `You are our favorite customer!`)
    // 3. complex exhaustive checking
    .exhaustive();

/**************************************************
 * Use case 3: Matching specific strings or numbers
 **************************************************/

const example3 = (queries: string[]) =>
  match(queries)
    .with(
      [
        P.string.startsWith('SELECT').endsWith('FROM user').select(),
        ...P.array(),
      ],
      (firstQuery) => `${firstQuery}: 👨‍👩‍👧‍👦`
    )
    .with(P.array(), () => 'other queries')
    .exhaustive();

const example4 = (position: { x: number; y: number }) =>
  match(position)
    .with({ x: P.number.gte(100) }, (value) => '⏱️')
    .with({ x: P.number.between(0, 100) }, (value) => '⏱️')
    .with({ x: P.number.positive(), y: P.number.positive() }, (value) => '⏱️')
    .otherwise(() => 'x or y is negative');

/******************************************
 * Use case 4: Validation an API response *
 ******************************************/

const User = {
  name: P.string,
  // 1. optional properties
  age: P.number.optional(),
  socialLinks: P.optional({
    twitter: P.string,
    instagram: P.string,
  }),
};

type User = P.infer<typeof User>;
/*    ^? {
    name: string;
    age?: number | undefined;
    socialLinks?: {
        twitter: string;
        instagram: string;
    } | undefined;
} */

const Post = {
  title: P.string.minLength(2).maxLength(255),
  stars: P.number.int().between(0, 5),
  content: P.string,
  author: User,
  // 2. arrays
  comments: P.array({ author: User, content: P.string }),
  // 3. tuples (a non-empty array in this case)
  tags: [P.string, ...P.array(P.string)],
} as const;

type Post = P.infer<typeof Post>;
/*    ^? {
    author: User;
    content: string;
    title: string;
    stars: number;
    comments: { author: User; content: string }[];
    tags: [string, ...string[]];
} */

// Elsewhere in the code:
// `fetch(...).then(validateResponse)`

const validateResponse = (response: unknown): Post | null => {
  // 3. validating unknown input with isMatching
  if (isMatching(Post, response)) {
    //  response is inferred as  `Post`.

    // Uncomment these lines if you want to try using `response`:
    // const cardTitle = `${response.title} by @${response.author.name}`;
    // const commenters = response.comments.map((c) => c.author.name).join(', ');
    return response;
  }

  return null;
};


================================================
FILE: examples/one-file-demo/package.json
================================================
{
  "name": "ts-pattern-examples",
  "version": "1.0.0",
  "main": "one-file-demo.ts",
  "author": "gvergnaud",
  "dependencies": {
    "ts-pattern": "^5.5.0"
  }
}

================================================
FILE: examples/one-file-demo/tsconfig.json
================================================
{
  "compilerOptions": {
    "strict": true,
    "lib": ["ES2015"],
    "target": "ES2015",
    "moduleResolution": "bundler",
    "module": "ESNext"
  }
}


================================================
FILE: jest.config.cjs
================================================
module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'node',
};


================================================
FILE: jsr.json
================================================
{
  "name": "@gabriel/ts-pattern",
  "version": "5.9.0",
  "exports": {
    ".": "./src/index.ts",
    "./types": "./src/index.ts",
    "./package.json": "./package.json"
  }
}

================================================
FILE: package.json
================================================
{
  "name": "ts-pattern",
  "version": "5.9.0",
  "description": " The exhaustive Pattern Matching library for TypeScript.",
  "type": "module",
  "sideEffects": false,
  "source": "src/index.ts",
  "exports": {
    ".": {
      "require": {
        "types": "./dist/index.d.cts",
        "default": "./dist/index.cjs"
      },
      "import": {
        "types": "./dist/index.d.ts",
        "default": "./dist/index.js"
      },
      "types": "./dist/index.d.ts",
      "default": "./dist/index.js"
    },
    "./types": {
      "require": {
        "types": "./dist/types/index.d.cts"
      },
      "import": {
        "types": "./dist/types/index.d.ts"
      },
      "types": "./dist/types/index.d.ts"
    },
    "./package.json": "./package.json"
  },
  "types": "dist/index.d.ts",
  "main": "dist/index.cjs",
  "module": "dist/index.js",
  "unpkg": "dist/index.umd.js",
  "scripts": {
    "build": "rimraf dist && microbundle --format modern,cjs,umd && sh ./scripts/generate-cts.sh",
    "dev": "microbundle watch",
    "prepublishOnly": "npm run test && npm run build",
    "publish:jsr": "npm run prepublishOnly && npx jsr publish",
    "release": "npm run prepublishOnly && npm publish && npx jsr publish",
    "test": "jest",
    "clear-test": "jest --clearCache",
    "fmt": "prettier ./src/** ./tests/** -w",
    "check": "tsc --strict --noEmit --extendedDiagnostics",
    "perf": "tsc --project tests/tsconfig.json --noEmit --extendedDiagnostics",
    "trace": "tsc --project tests/tsconfig.json --generateTrace trace --incremental false  --noEmit",
    "analyzeTrace": "npx @typescript/analyze-trace trace"
  },
  "files": [
    "dist/**/*",
    "package.json"
  ],
  "repository": {
    "type": "git",
    "url": "git+ssh://git@github.com/gvergnaud/ts-pattern.git"
  },
  "keywords": [
    "pattern",
    "matching",
    "pattern-matching",
    "typescript",
    "match-with",
    "match",
    "switch",
    "adt"
  ],
  "author": "Gabriel Vergnaud",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/gvergnaud/ts-pattern/issues"
  },
  "homepage": "https://github.com/gvergnaud/ts-pattern#readme",
  "devDependencies": {
    "@types/jest": "^30.0.0",
    "jest": "^30.1.3",
    "microbundle": "^0.15.1",
    "prettier": "^2.8.8",
    "rimraf": "^5.0.1",
    "ts-jest": "^29.4.1",
    "typescript": "^5.9.2"
  }
}


================================================
FILE: scripts/generate-cts.sh
================================================
#!/bin/bash

# TypeScript projects using `moduleResolution: nodenext` expect
# explicit extensions to be included in declaration files,
# and to have a different set of declarations for commonjs
# modules (.d.cts) and ES modules (.d.ts). `tsc` unfortunately
# doesn't provide a way to generate these declarations files,
# so I'm manually creating them in this script.

files=$(find dist -type f -name "*.d.ts");

# Loop through the declaration files
for file in $files; do
    # Update imports to include the '.cjs' extension
    sed -E "s/(.*)from '([^']*)'/\1from '\2.cjs'/g" "$file" > "${file%.d.ts}.d.cts"
    # add `.js` extensions to .d.ts files
    sed -i '' -e "s/\(.*\)from '\([^']*\)'/\1from '\2.js'/g" "$file"
done

================================================
FILE: src/errors.ts
================================================
/**
 * Error when the given input value does not match any included pattern
 * and .exhaustive() was specified
 */
export class NonExhaustiveError extends Error {
  constructor(public input: unknown) {
    let displayedValue;
    try {
      displayedValue = JSON.stringify(input);
    } catch (e) {
      displayedValue = input;
    }
    super(`Pattern matching error: no pattern matches value ${displayedValue}`);
  }
}


================================================
FILE: src/index.ts
================================================
import * as Pattern from './patterns';

export { match } from './match';
export { isMatching } from './is-matching';
export { Pattern, Pattern as P };
export { NonExhaustiveError } from './errors';


================================================
FILE: src/internals/helpers.ts
================================================
/**
 * @module
 * @private
 * @internal
 */

import * as symbols from './symbols';
import { SelectionType } from '../types/FindSelected';
import { Pattern, Matcher, MatcherType, AnyMatcher } from '../types/Pattern';

// @internal
export const isObject = (value: unknown): value is Object =>
  Boolean(value && typeof value === 'object');

//   @internal
export const isMatcher = (
  x: unknown
): x is Matcher<unknown, unknown, MatcherType, SelectionType> => {
  const pattern = x as Matcher<unknown, unknown, MatcherType, SelectionType>;
  return pattern && !!pattern[symbols.matcher];
};

// @internal
const isOptionalPattern = (
  x: unknown
): x is Matcher<unknown, unknown, 'optional', SelectionType> => {
  return isMatcher(x) && x[symbols.matcher]().matcherType === 'optional';
};

// tells us if the value matches a given pattern.
// @internal
export const matchPattern = (
  pattern: any,
  value: any,
  select: (key: string, value: unknown) => void
): boolean => {
  if (isMatcher(pattern)) {
    const matcher = pattern[symbols.matcher]();
    const { matched, selections } = matcher.match(value);
    if (matched && selections) {
      Object.keys(selections).forEach((key) => select(key, selections[key]));
    }
    return matched;
  }

  if (isObject(pattern)) {
    if (!isObject(value)) return false;

    // Tuple pattern
    if (Array.isArray(pattern)) {
      if (!Array.isArray(value)) return false;
      let startPatterns = [];
      let endPatterns = [];
      let variadicPatterns: AnyMatcher[] = [];

      for (const i of pattern.keys()) {
        const subpattern = pattern[i];
        if (isMatcher(subpattern) && subpattern[symbols.isVariadic]) {
          variadicPatterns.push(subpattern);
        } else if (variadicPatterns.length) {
          endPatterns.push(subpattern);
        } else {
          startPatterns.push(subpattern);
        }
      }

      if (variadicPatterns.length) {
        if (variadicPatterns.length > 1) {
          throw new Error(
            `Pattern error: Using \`...P.array(...)\` several times in a single pattern is not allowed.`
          );
        }

        if (value.length < startPatterns.length + endPatterns.length) {
          return false;
        }

        const startValues = value.slice(0, startPatterns.length);
        const endValues =
          endPatterns.length === 0 ? [] : value.slice(-endPatterns.length);
        const middleValues = value.slice(
          startPatterns.length,
          endPatterns.length === 0 ? Infinity : -endPatterns.length
        );

        return (
          startPatterns.every((subPattern, i) =>
            matchPattern(subPattern, startValues[i], select)
          ) &&
          endPatterns.every((subPattern, i) =>
            matchPattern(subPattern, endValues[i], select)
          ) &&
          (variadicPatterns.length === 0
            ? true
            : matchPattern(variadicPatterns[0], middleValues, select))
        );
      }

      return pattern.length === value.length
        ? pattern.every((subPattern, i) =>
            matchPattern(subPattern, value[i], select)
          )
        : false;
    }

    return Reflect.ownKeys(pattern).every((k): boolean => {
      const subPattern = pattern[k];

      return (
        (k in value || isOptionalPattern(subPattern)) &&
        matchPattern(subPattern, value[k], select)
      );
    });
  }

  return Object.is(value, pattern);
};

// @internal
export const getSelectionKeys = (pattern: any): string[] => {
  if (isObject(pattern)) {
    if (isMatcher(pattern)) {
      return pattern[symbols.matcher]().getSelectionKeys?.() ?? [];
    }
    if (Array.isArray(pattern)) return flatMap(pattern, getSelectionKeys);
    return flatMap(Object.values(pattern), getSelectionKeys);
  }
  return [];
};

// @internal
export const flatMap = <a, b>(
  xs: readonly a[],
  f: (v: a) => readonly b[]
): b[] => xs.reduce<b[]>((acc, x) => acc.concat(f(x)), []);


================================================
FILE: src/internals/symbols.ts
================================================
/**
 * Symbols used internally within ts-pattern to construct and discriminate
 * Guard, Not, and Select, and AnonymousSelect patterns
 *
 * Symbols have the advantage of not appearing in auto-complete suggestions in
 * user defined patterns, and eliminate the risk of property
 * overlap between ts-pattern internals and user defined patterns.
 *
 * These symbols have to be visible to tsc for type inference to work, but
 * users should not import them
 * @module
 * @private
 * @internal
 */

export const matcher = Symbol.for('@ts-pattern/matcher');
export type matcher = typeof matcher;

export const unset = Symbol.for('@ts-pattern/unset');
export type unset = typeof unset;

export const isVariadic = Symbol.for('@ts-pattern/isVariadic');
export type isVariadic = typeof isVariadic;

// can't be a symbol because this key has to be enumerable.
export const anonymousSelectKey = '@ts-pattern/anonymous-select-key';
export type anonymousSelectKey = typeof anonymousSelectKey;

export const override = Symbol.for('@ts-pattern/override');
export type override = typeof override;


================================================
FILE: src/is-matching.ts
================================================
import { MatchedValue, Pattern, UnknownProperties } from './types/Pattern';
import * as P from './patterns';
import { matchPattern } from './internals/helpers';
import { WithDefault } from './types/helpers';

/**
 * This constraint allows using additional properties
 * in object patterns. See "should allow targetting unknown properties"
 * unit test in `is-matching.test.ts`.
 */
type PatternConstraint<T> = T extends readonly any[]
  ? P.Pattern<T>
  : T extends object
  ? P.Pattern<T> & UnknownProperties
  : P.Pattern<T>;

/**
 * `isMatching` takes pattern and returns a **type guard** function, cheching if a value matches this pattern.
 *
 * [Read  documentation for `isMatching` on GitHub](https://github.com/gvergnaud/ts-pattern#ismatching)
 *
 * @example
 *  const hasName = isMatching({ name: P.string })
 *
 *  declare let input: unknown
 *
 *  if (hasName(input)) {
 *    // `input` inferred as { name: string }
 *    return input.name
 *  }
 */
export function isMatching<const p extends Pattern<unknown>>(
  pattern: p
): (value: unknown) => value is P.infer<p>;
/**
 * `isMatching` takes pattern and a value and checks if the value matches this pattern.
 *
 * [Read  documentation for `isMatching` on GitHub](https://github.com/gvergnaud/ts-pattern#ismatching)
 *
 * @example
 *  declare let input: unknown
 *
 *  if (isMatching({ name: P.string }, input)) {
 *    // `input` inferred as { name: string }
 *    return input.name
 *  }
 */
export function isMatching<const T, const P extends PatternConstraint<T>>(
  pattern: P,
  value: T
): value is T & WithDefault<P.narrow<T, P>, P.infer<P>>;

export function isMatching<const p extends Pattern<any>>(
  ...args: [pattern: p, value?: any]
): boolean | ((vale: any) => boolean) {
  if (args.length === 1) {
    const [pattern] = args;
    return (value: any): value is MatchedValue<any, P.infer<p>> =>
      matchPattern(pattern, value, () => {});
  }
  if (args.length === 2) {
    const [pattern, value] = args;
    return matchPattern(pattern, value, () => {});
  }

  throw new Error(
    `isMatching wasn't given the right number of arguments: expected 1 or 2, received ${args.length}.`
  );
}


================================================
FILE: src/match.ts
================================================
import { Pattern } from './types/Pattern';
import { Match } from './types/Match';
import * as symbols from './internals/symbols';
import { matchPattern } from './internals/helpers';
import { NonExhaustiveError } from './errors';

type MatchState<output> =
  | { matched: true; value: output }
  | { matched: false; value: undefined };

const unmatched: MatchState<never> = {
  matched: false,
  value: undefined,
};

/**
 * `match` creates a **pattern matching expression**.
 *  * Use `.with(pattern, handler)` to pattern match on the input.
 *  * Use `.exhaustive()` or `.otherwise(() => defaultValue)` to end the expression and get the result.
 *
 * [Read the documentation for `match` on GitHub](https://github.com/gvergnaud/ts-pattern#match)
 *
 * @example
 *  declare let input: "A" | "B";
 *
 *  return match(input)
 *    .with("A", () => "It's an A!")
 *    .with("B", () => "It's a B!")
 *    .exhaustive();
 *
 */
export function match<const input, output = symbols.unset>(
  value: input
): Match<input, output> {
  return new MatchExpression(value, unmatched) as any;
}

/**
 * This class represents a match expression. It follows the
 * builder pattern, we chain methods to add features to the expression
 * until we call `.exhaustive`, `.otherwise` or the unsafe `.run`
 * method to execute it.
 *
 * The types of this class aren't public, the public type definition
 * can be found in src/types/Match.ts.
 */
class MatchExpression<input, output> {
  constructor(private input: input, private state: MatchState<output>) {}

  with(...args: any[]): MatchExpression<input, output> {
    if (this.state.matched) return this;

    const handler: (selection: unknown, value: input) => output =
      args[args.length - 1];

    const patterns: Pattern<input>[] = [args[0]];
    let predicate: ((value: input) => unknown) | undefined = undefined;

    if (args.length === 3 && typeof args[1] === 'function') {
      // case with guard as second argument
      predicate = args[1];
    } else if (args.length > 2) {
      // case with several patterns
      patterns.push(...args.slice(1, args.length - 1));
    }

    let hasSelections = false;
    let selected: Record<string, unknown> = {};
    const select = (key: string, value: unknown) => {
      hasSelections = true;
      selected[key] = value;
    };

    const matched =
      patterns.some((pattern) => matchPattern(pattern, this.input, select)) &&
      (predicate ? Boolean(predicate(this.input)) : true);

    const selections = hasSelections
      ? symbols.anonymousSelectKey in selected
        ? selected[symbols.anonymousSelectKey]
        : selected
      : this.input;

    const state = matched
      ? {
          matched: true as const,
          value: handler(selections, this.input),
        }
      : unmatched;

    return new MatchExpression(this.input, state);
  }

  when(
    predicate: (value: input) => unknown,
    handler: (selection: input, value: input) => output
  ): MatchExpression<input, output> {
    if (this.state.matched) return this;

    const matched = Boolean(predicate(this.input));

    return new MatchExpression<input, output>(
      this.input,
      matched
        ? { matched: true, value: handler(this.input, this.input) }
        : unmatched
    );
  }

  otherwise(handler: (value: input) => output): output {
    if (this.state.matched) return this.state.value;
    return handler(this.input);
  }

  exhaustive(unexpectedValueHandler = defaultCatcher): output {
    if (this.state.matched) return this.state.value;
    return unexpectedValueHandler(this.input);
  }

  run(): output {
    return this.exhaustive();
  }

  returnType() {
    return this;
  }

  narrow() {
    return this;
  }
}

function defaultCatcher(input: unknown): never {
  throw new NonExhaustiveError(input);
}


================================================
FILE: src/patterns.ts
================================================
/**
 * The `P` module contains patterns for primitive types, wildcards and
 * other pattern-matching utilities.
 *
 * @module
 */

import { matchPattern, getSelectionKeys, flatMap } from './internals/helpers';
import * as symbols from './internals/symbols';
import { matcher } from './internals/symbols';
import { isMatching } from './is-matching';
import { ExtractPreciseValue } from './types/ExtractPreciseValue';
import { Fn } from './types/helpers';
import { InvertPattern } from './types/InvertPattern';
import {
  Pattern,
  UnknownValuePattern,
  OptionalP,
  ArrayP,
  MapP,
  SetP,
  AndP,
  OrP,
  NotP,
  GuardP,
  SelectP,
  AnonymousSelectP,
  GuardExcludeP,
  CustomP,
  Matcher,
  StringPattern,
  UnknownPattern,
  NumberPattern,
  BooleanPattern,
  BigIntPattern,
  NullishPattern,
  SymbolPattern,
  Chainable,
  BigIntChainable,
  NumberChainable,
  StringChainable,
  ArrayChainable,
  Variadic,
  NonNullablePattern,
  RecordP,
} from './types/Pattern';

export type {
  /**
   * `Pattern<T>` is the type of all patterns
   * that can match a value of type `T`.
   */
  Pattern,

  /**
   * `unstable_Fn` can be used to created a
   * a Matchable instance – a custom type that
   * can be used as a pattern.
   *
   * @experimental This feature is unstable.
   */
  Fn as unstable_Fn,
};

export { matcher };

/**
 * A `Matchable` is an object implementing
 * the Matcher Protocol. It must have a `[P.matcher]: P.Matcher<NarrowFn>`
 * key, which defines how this object should be matched by TS-Pattern.
 *
 * @experimental This feature is unstable.
 *
 * @example
 * ```ts
 * class Some<T> implements P.unstable_Matchable {
 *  [P.matcher](): P.unstable_Matcher<Some<T>>
 * }
 * ```
 */
export type unstable_Matchable<
  narrowedOrFn,
  input = unknown,
  pattern = never
> = CustomP<input, pattern, narrowedOrFn>;

/**
 * A `Matcher` is an object with `match` function, which
 * defines how this object should be matched by TS-Pattern.
 *
 * @experimental This feature is unstable.
 *
 * @example
 * ```ts
 * class Some<T> implements P.unstable_Matchable {
 *  [P.matcher](): P.unstable_Matcher<Some<T>>
 * }
 * ```
 */
export type unstable_Matcher<
  narrowedOrFn,
  input = unknown,
  pattern = never
> = ReturnType<CustomP<input, pattern, narrowedOrFn>[matcher]>;

/**
 * `P.infer<typeof somePattern>` will return the type of the value
 * matched by this pattern.
 *
 * [Read the documentation for `P.infer` on GitHub](https://github.com/gvergnaud/ts-pattern#pinfer)
 *
 * @example
 * const userPattern = { name: P.string }
 * type User = P.infer<typeof userPattern>
 */
export type infer<pattern> = InvertPattern<NoInfer<pattern>, unknown>;

/**
 * `P.narrow<Input, Pattern>` will narrow the input type to only keep
 * the set of values that are compatible with the provided pattern type.
 *
 * [Read the documentation for `P.narrow` on GitHub](https://github.com/gvergnaud/ts-pattern#pnarrow)
 *
 * @example
 * type Input = ['a' | 'b' | 'c', 'a' | 'b' | 'c']
 * const Pattern = ['a', P.union('a', 'b')] as const
 *
 * type Narrowed = P.narrow<Input, typeof Pattern>
 * //     ^? ['a', 'a' | 'b']
 */
export type narrow<input, pattern> = ExtractPreciseValue<
  input,
  InvertPattern<pattern, input>
>;

function chainable<pattern extends Matcher<any, any, any, any, any>>(
  pattern: pattern
): Chainable<pattern> {
  return Object.assign(pattern, {
    optional: () => optional(pattern),
    and: (p2: any) => intersection(pattern, p2),
    or: (p2: any) => union(pattern, p2),
    select: (key: any) =>
      key === undefined ? select(pattern) : select(key, pattern),
  }) as Chainable<pattern>;
}

const variadic = <pattern extends {}>(pattern: pattern): Variadic<pattern> =>
  Object.assign(pattern, {
    [Symbol.iterator](): Iterator<pattern, void, undefined> {
      let i = 0;
      const variadicPattern = Object.assign(pattern, {
        [symbols.isVariadic]: true,
      });
      const values: IteratorResult<pattern, void>[] = [
        { value: variadicPattern, done: false },
        { done: true, value: undefined },
      ];
      return {
        next: () => values[i++] ?? values.at(-1)!,
      };
    },
  });

function arrayChainable<pattern extends Matcher<any, any, any, any, any>>(
  pattern: pattern
): ArrayChainable<pattern> {
  return Object.assign(variadic(pattern), {
    optional: () => arrayChainable(optional(pattern)),
    select: (key: any) =>
      arrayChainable(
        key === undefined ? select(pattern) : select(key, pattern)
      ),
  }) as any;
}

/**
 * `P.optional(subpattern)` takes a sub pattern and returns a pattern which matches if the
 * key is undefined or if it is defined and the sub pattern matches its value.
 *
 * [Read the documentation for `P.optional` on GitHub](https://github.com/gvergnaud/ts-pattern#poptional-patterns)
 *
 * @example
 *  match(value)
 *   .with({ greeting: P.optional('Hello') }, () => 'will match { greeting?: "Hello" }')
 */
export function optional<
  input,
  const pattern extends unknown extends input
    ? UnknownValuePattern
    : Pattern<input>
>(pattern: pattern): Chainable<OptionalP<input, pattern>, 'optional'> {
  return chainable({
    [matcher]() {
      return {
        match: <UnknownInput>(value: UnknownInput | input) => {
          let selections: Record<string, unknown[]> = {};
          const selector = (key: string, value: any) => {
            selections[key] = value;
          };
          if (value === undefined) {
            getSelectionKeys(pattern).forEach((key) =>
              selector(key, undefined)
            );
            return { matched: true, selections };
          }
          const matched = matchPattern(pattern, value, selector);
          return { matched, selections };
        },
        getSelectionKeys: () => getSelectionKeys(pattern),
        matcherType: 'optional',
      };
    },
  });
}

type UnwrapArray<xs> = xs extends readonly (infer x)[] ? x : never;

type UnwrapSet<xs> = xs extends Set<infer x> ? x : never;

type UnwrapMapKey<xs> = xs extends Map<infer k, any> ? k : never;

type UnwrapMapValue<xs> = xs extends Map<any, infer v> ? v : never;

type UnwrapRecordKey<xs> = xs extends Record<infer k, any> ? k : never;

type UnwrapRecordValue<xs> = xs extends Record<any, infer v> ? v : never;

type WithDefault<a, b> = [a] extends [never] ? b : a;

/**
 * `P.array(subpattern)` takes a sub pattern and returns a pattern, which matches
 * arrays if all their elements match the sub pattern.
 *
 * [Read the documentation for `P.array` on GitHub](https://github.com/gvergnaud/ts-pattern#parray-patterns)
 *
 * @example
 *  match(value)
 *   .with({ users: P.array({ name: P.string }) }, () => 'will match { name: string }[]')
 */
export function array<input>(): ArrayChainable<ArrayP<input, unknown>>;
export function array<
  input,
  const pattern extends Pattern<WithDefault<UnwrapArray<input>, unknown>>
>(pattern: pattern): ArrayChainable<ArrayP<input, pattern>>;
export function array(
  ...args: [pattern?: any]
): ArrayChainable<ArrayP<any, any>> {
  return arrayChainable({
    [matcher]() {
      return {
        match: (value: any) => {
          if (!Array.isArray(value)) return { matched: false };

          if (args.length === 0) return { matched: true };

          const pattern = args[0];
          let selections: Record<string, unknown[]> = {};

          if (value.length === 0) {
            getSelectionKeys(pattern).forEach((key) => {
              selections[key] = [];
            });
            return { matched: true, selections };
          }

          const selector = (key: string, value: unknown) => {
            selections[key] = (selections[key] || []).concat([value]);
          };

          const matched = value.every((v) =>
            matchPattern(pattern, v, selector)
          );

          return { matched, selections };
        },
        getSelectionKeys: () =>
          args.length === 0 ? [] : getSelectionKeys(args[0]),
      };
    },
  });
}

/**
 * `P.set(subpattern)` takes a sub pattern and returns a pattern that matches
 * sets if all their elements match the sub pattern.
 *
 * [Read `P.set` documentation on GitHub](https://github.com/gvergnaud/ts-pattern#pset-patterns)
 *
 * @example
 *  match(value)
 *   .with({ users: P.set(P.string) }, () => 'will match Set<string>')
 */
export function set<input>(): Chainable<SetP<input, unknown>>;
export function set<
  input,
  const pattern extends Pattern<WithDefault<UnwrapSet<input>, unknown>>
>(pattern: pattern): Chainable<SetP<input, pattern>>;
export function set<
  input,
  const pattern extends Pattern<WithDefault<UnwrapSet<input>, unknown>>
>(...args: [pattern?: pattern]): Chainable<SetP<input, pattern>> {
  return chainable({
    [matcher]() {
      return {
        match: <UnknownInput>(value: UnknownInput | input) => {
          if (!(value instanceof Set)) return { matched: false };

          let selections: Record<string, unknown[]> = {};

          if (value.size === 0) {
            return { matched: true, selections };
          }

          if (args.length === 0) return { matched: true };

          const selector = (key: string, value: unknown) => {
            selections[key] = (selections[key] || []).concat([value]);
          };

          const pattern = args[0];

          const matched = setEvery(value, (v) =>
            matchPattern(pattern, v, selector)
          );

          return { matched, selections };
        },
        getSelectionKeys: () =>
          args.length === 0 ? [] : getSelectionKeys(args[0]),
      };
    },
  });
}

const setEvery = <T>(set: Set<T>, predicate: (value: T) => boolean) => {
  for (const value of set) {
    if (predicate(value)) continue;
    return false;
  }
  return true;
};

/**
 * `P.map(keyPattern, valuePattern)` takes a subpattern to match against the
 * key, a subpattern to match against the value and returns a pattern that
 * matches on maps where all elements inside the map match those two
 * subpatterns.
 *
 * [Read `P.map` documentation on GitHub](https://github.com/gvergnaud/ts-pattern#pmap-patterns)
 *
 * @example
 *  match(value)
 *   .with({ users: P.map(P.string, P.number) }, (map) => `map's type is Map<string, number>`)
 */
export function map<input>(): Chainable<MapP<input, unknown, unknown>>;
export function map<
  input,
  const pkey extends Pattern<WithDefault<UnwrapMapKey<input>, unknown>>,
  const pvalue extends Pattern<WithDefault<UnwrapMapValue<input>, unknown>>
>(patternKey: pkey, patternValue: pvalue): Chainable<MapP<input, pkey, pvalue>>;
export function map<
  input,
  const pkey extends Pattern<WithDefault<UnwrapMapKey<input>, unknown>>,
  const pvalue extends Pattern<WithDefault<UnwrapMapValue<input>, unknown>>
>(
  ...args: [patternKey?: pkey, patternValue?: pvalue]
): Chainable<MapP<input, pkey, pvalue>> {
  return chainable({
    [matcher]() {
      return {
        match: <UnknownInput>(value: UnknownInput | input) => {
          if (!(value instanceof Map)) return { matched: false };

          let selections: Record<string, unknown[]> = {};

          if (value.size === 0) {
            return { matched: true, selections };
          }

          const selector = (key: string, value: unknown) => {
            selections[key] = (selections[key] || []).concat([value]);
          };

          if (args.length === 0) return { matched: true };
          if (args.length === 1) {
            throw new Error(
              `\`P.map\` wasn\'t given enough arguments. Expected (key, value), received ${args[0]?.toString()}`
            );
          }
          const [patternKey, patternValue] = args;

          const matched = mapEvery(value, (v, k) => {
            const keyMatch = matchPattern(patternKey, k, selector);
            const valueMatch = matchPattern(patternValue, v, selector);
            return keyMatch && valueMatch;
          });

          return { matched, selections };
        },
        getSelectionKeys: () =>
          args.length === 0
            ? []
            : [...getSelectionKeys(args[0]), ...getSelectionKeys(args[1])],
      };
    },
  });
}

const mapEvery = <K, T>(
  map: Map<K, T>,
  predicate: (value: T, key: K) => boolean
) => {
  for (const [key, value] of map.entries()) {
    if (predicate(value, key)) continue;
    return false;
  }
  return true;
};

/**
 * `P.record(keyPattern, valuePattern)` takes a subpattern to match against the
 * key, a subpattern to match against the value and returns a pattern that
 * matches on objects where all entries match those two
 * subpatterns.
 *
 * [Read `P.record` documentation on GitHub](https://github.com/gvergnaud/ts-pattern#precord-patterns)
 *
 * @example
 *  match(value)
 *   .with({ users: P.record(P.string, P.number) }, (obj) => `object's type is Record<string, number>`)
 */
export function record<
  input,
  const pvalue extends Pattern<UnwrapRecordValue<input>>
>(patternValue: pvalue): Chainable<RecordP<input, StringPattern, pvalue>>;
export function record<
  input,
  const pkey extends Pattern<WithDefault<UnwrapRecordKey<input>, PropertyKey>>,
  const pvalue extends Pattern<WithDefault<UnwrapRecordValue<input>, unknown>>
>(
  patternKey: pkey,
  patternValue?: pvalue
): Chainable<RecordP<input, pkey, pvalue>>;
export function record(
  ...args: [patternKey?: unknown, patternValue?: unknown]
): Chainable<RecordP<unknown, unknown, unknown>> {
  return chainable({
    [matcher]() {
      return {
        match: (value: unknown) => {
          if (
            value === null ||
            typeof value !== 'object' ||
            Array.isArray(value)
          ) {
            return { matched: false };
          }

          if (args.length === 0) {
            throw new Error(
              `\`P.record\` wasn\'t given enough arguments. Expected (value) or (key, value), received ${args[0]?.toString()}`
            );
          }

          let selections: Record<string, unknown[]> = {};

          const selector = (key: string, value: unknown) => {
            selections[key] = (selections[key] || []).concat([value]);
          };

          const [patternKey, patternValue] =
            args.length === 1 ? [string, args[0]] : args;

          const matched = recordEvery(value, (k, v) => {
            // since number keys are coerced to strings, we need to coerce them back to numbers if the pattern is `number`
            const coercedKey =
              typeof k === 'string' && !Number.isNaN(Number(k))
                ? Number(k)
                : null;

            const coercedKeyMatch =
              coercedKey !== null
                ? matchPattern(patternKey, coercedKey, selector)
                : false;

            const keyMatch = matchPattern(patternKey, k, selector);

            const valueMatch = matchPattern(patternValue, v, selector);

            return (keyMatch || coercedKeyMatch) && valueMatch;
          });

          return { matched, selections };
        },
        getSelectionKeys: () =>
          args.length === 0
            ? []
            : [...getSelectionKeys(args[0]), ...getSelectionKeys(args[1])],
      };
    },
  });
}

const recordEvery = <K extends PropertyKey, T>(
  record: Record<K, T>,
  predicate: (key: K, value: T) => boolean
) => {
  const keys = Reflect.ownKeys(record);
  for (const key of keys) {
    if (predicate(key as K, record[key as K] as T)) continue;
    return false;
  }
  return true;
};

/**
 * `P.intersection(...patterns)` returns a pattern which matches
 * only if **every** patterns provided in parameter match the input.
 *
 * [Read the documentation for `P.intersection` on GitHub](https://github.com/gvergnaud/ts-pattern#pintersection-patterns)
 *
 * @example
 *  match(value)
 *   .with(
 *     {
 *       user: P.intersection(
 *         { firstname: P.string },
 *         { lastname: P.string },
 *         { age: P.when(age => age > 21) }
 *       )
 *     },
 *     ({ user }) => 'will match { firstname: string, lastname: string, age: number } if age > 21'
 *   )
 */
export function intersection<
  input,
  const patterns extends readonly [Pattern<input>, ...Pattern<input>[]]
>(...patterns: patterns): Chainable<AndP<input, patterns>> {
  return chainable({
    [matcher]: () => ({
      match: (value) => {
        let selections: Record<string, unknown[]> = {};
        const selector = (key: string, value: any) => {
          selections[key] = value;
        };
        const matched = (patterns as readonly UnknownValuePattern[]).every(
          (p) => matchPattern(p, value, selector)
        );
        return { matched, selections };
      },
      getSelectionKeys: () =>
        flatMap(patterns as readonly UnknownValuePattern[], getSelectionKeys),
      matcherType: 'and',
    }),
  });
}

/**
 * `P.union(...patterns)` returns a pattern which matches
 * if **at least one** of the patterns provided in parameter match the input.
 *
 * [Read the documentation for `P.union` on GitHub](https://github.com/gvergnaud/ts-pattern#punion-patterns)
 *
 * @example
 *  match(value)
 *   .with(
 *     { type: P.union('a', 'b', 'c') },
 *     ({ type }) => 'will match { type: "a" | "b" | "c" }'
 *   )
 */
export function union<
  input,
  const patterns extends readonly [Pattern<input>, ...Pattern<input>[]]
>(...patterns: patterns): Chainable<OrP<input, patterns>> {
  return chainable({
    [matcher]: () => ({
      match: <UnknownInput>(value: UnknownInput | input) => {
        let selections: Record<string, unknown[]> = {};
        const selector = (key: string, value: any) => {
          selections[key] = value;
        };
        flatMap(
          patterns as readonly UnknownValuePattern[],
          getSelectionKeys
        ).forEach((key) => selector(key, undefined));
        const matched = (patterns as readonly UnknownValuePattern[]).some((p) =>
          matchPattern(p, value, selector)
        );
        return { matched, selections };
      },
      getSelectionKeys: () =>
        flatMap(patterns as readonly UnknownValuePattern[], getSelectionKeys),
      matcherType: 'or',
    }),
  });
}

/**
 * `P.not(pattern)` returns a pattern which matches if the sub pattern
 * doesn't match.
 *
 * [Read the documentation for `P.not` on GitHub](https://github.com/gvergnaud/ts-pattern#pnot-patterns)
 *
 * @example
 *  match<{ a: string | number }>(value)
 *   .with({ a: P.not(P.string) }, (x) => 'will match { a: number }'
 *   )
 */

export function not<
  input,
  const pattern extends Pattern<input> | UnknownValuePattern
>(pattern: pattern): Chainable<NotP<input, pattern>> {
  return chainable({
    [matcher]: () => ({
      match: <UnknownInput>(value: UnknownInput | input) => ({
        matched: !matchPattern(pattern, value, () => {}),
      }),
      getSelectionKeys: () => [],
      matcherType: 'not',
    }),
  });
}

/**
 * `P.when((value) => boolean)` returns a pattern which matches
 * if the predicate returns true for the current input.
 *
 * [Read the documentation for `P.when` on GitHub](https://github.com/gvergnaud/ts-pattern#pwhen-patterns)
 *
 * @example
 *  match<{ age: number }>(value)
 *   .with({ age: P.when(age => age > 21) }, (x) => 'will match if value.age > 21'
 *   )
 */
export function when<input, predicate extends (value: input) => unknown>(
  predicate: predicate
): GuardP<
  input,
  predicate extends (value: any) => value is infer narrowed ? narrowed : never
>;
export function when<input, narrowed extends input, excluded>(
  predicate: (input: input) => input is narrowed
): GuardExcludeP<input, narrowed, excluded>;
export function when<input, predicate extends (value: input) => unknown>(
  predicate: predicate
): GuardP<
  input,
  predicate extends (value: any) => value is infer narrowed ? narrowed : never
> {
  return {
    [matcher]: () => ({
      match: <UnknownInput>(value: UnknownInput | input) => ({
        matched: Boolean(predicate(value as input)),
      }),
    }),
  };
}

/**
 * `P.select()` is a pattern which will always match,
 * and will inject the selected piece of input in the handler function.
 *
 * [Read the documentation for `P.select` on GitHub](https://github.com/gvergnaud/ts-pattern#pselect-patterns)
 *
 * @example
 *  match<{ age: number }>(value)
 *   .with({ age: P.select() }, (age) => 'age: number'
 *   )
 */
export function select(): Chainable<AnonymousSelectP, 'select' | 'or' | 'and'>;
export function select<
  input,
  const patternOrKey extends
    | string
    | (unknown extends input ? UnknownValuePattern : Pattern<input>)
>(
  patternOrKey: patternOrKey
): patternOrKey extends string
  ? Chainable<SelectP<patternOrKey, 'select' | 'or' | 'and'>>
  : Chainable<
      SelectP<symbols.anonymousSelectKey, input, patternOrKey>,
      'select' | 'or' | 'and'
    >;
export function select<
  input,
  const pattern extends unknown extends input
    ? UnknownValuePattern
    : Pattern<input>,
  const k extends string
>(
  key: k,
  pattern: pattern
): Chainable<SelectP<k, input, pattern>, 'select' | 'or' | 'and'>;
export function select(
  ...args: [keyOrPattern?: unknown | string, pattern?: unknown]
): Chainable<SelectP<string>, 'select' | 'or' | 'and'> {
  const key: string | undefined =
    typeof args[0] === 'string' ? args[0] : undefined;
  const pattern: unknown =
    args.length === 2
      ? args[1]
      : typeof args[0] === 'string'
      ? undefined
      : args[0];
  return chainable({
    [matcher]() {
      return {
        match: (value) => {
          let selections: Record<string, unknown> = {
            [key ?? symbols.anonymousSelectKey]: value,
          };
          const selector = (key: string, value: any) => {
            selections[key] = value;
          };
          return {
            matched:
              pattern === undefined
                ? true
                : matchPattern(pattern, value, selector),
            selections: selections,
          };
        },
        getSelectionKeys: () =>
          [key ?? symbols.anonymousSelectKey].concat(
            pattern === undefined ? [] : getSelectionKeys(pattern)
          ),
      };
    },
  });
}

function isUnknown(x: unknown): x is unknown {
  return true;
}

function isNumber<T>(x: T | number): x is number {
  return typeof x === 'number';
}

function isString<T>(x: T | string): x is string {
  return typeof x === 'string';
}

function isBoolean<T>(x: T | boolean): x is boolean {
  return typeof x === 'boolean';
}

function isBigInt<T>(x: T | bigint): x is bigint {
  return typeof x === 'bigint';
}

function isSymbol<T>(x: T | symbol): x is symbol {
  return typeof x === 'symbol';
}

function isNullish<T>(x: T | null | undefined): x is null | undefined {
  return x === null || x === undefined;
}

function isNonNullable(x: unknown): x is {} {
  return x !== null && x !== undefined;
}

type AnyConstructor = abstract new (...args: any[]) => any;

function isInstanceOf<T extends AnyConstructor>(classConstructor: T) {
  return (val: unknown): val is InstanceType<T> =>
    val instanceof classConstructor;
}

/**
 * `P.any` is a wildcard pattern, matching **any value**.
 *
 * [Read the documentation for `P.any` on GitHub](https://github.com/gvergnaud/ts-pattern#p_-wildcard)
 *
 * @example
 *  match(value)
 *   .with(P.any, () => 'will always match')
 */
export const any: UnknownPattern = chainable(when(isUnknown));

/**
 * `P.unknown` is a wildcard pattern, matching **unknown value**.
 *
 * [Read the documentation for `P.unknown` on GitHub](https://github.com/gvergnaud/ts-pattern#p_-wildcard)
 *
 * @example
 *  match(value)
 *   .with(P.unknown, () => 'will always match')
 */
export const unknown: UnknownPattern = chainable(when(isUnknown));

/**
 * `P._` is a wildcard pattern, matching **any value**.
 * It's an alias to `P.any`.
 *
 * [Read the documentation for `P._` on GitHub](https://github.com/gvergnaud/ts-pattern#p_-wildcard)
 *
 * @example
 *  match(value)
 *   .with(P._, () => 'will always match')
 */
export const _ = any;

/**
 * `P.string.startsWith(start)` is a pattern, matching **strings** starting with `start`.
 *
 * [Read the documentation for `P.string.startsWith` on GitHub](https://github.com/gvergnaud/ts-pattern#pstringstartsWith)
 *
 * @example
 *  match(value)
 *   .with(P.string.startsWith('A'), () => 'value starts with an A')
 */

const startsWith = <input, const start extends string>(
  start: start
): GuardP<input, `${start}${string}`> =>
  when((value) => isString(value) && value.startsWith(start));

/**
 * `P.string.endsWith(end)` is a pattern, matching **strings** ending with `end`.
 *
 * [Read the documentation for `P.string.endsWith` on GitHub](https://github.com/gvergnaud/ts-pattern#pstringendsWith)
 *
 * @example
 *  match(value)
 *   .with(P.string.endsWith('!'), () => 'value ends with an !')
 */
const endsWith = <input, const end extends string>(
  end: end
): GuardP<input, `${string}${end}`> =>
  when((value) => isString(value) && value.endsWith(end));

/**
 * `P.string.minLength(min)` is a pattern, matching **strings** with at least `min` characters.
 *
 * [Read the documentation for `P.string.minLength` on GitHub](https://github.com/gvergnaud/ts-pattern#pstringminLength)
 *
 * @example
 *  match(value)
 *   .with(P.string.minLength(10), () => 'string with more length >= 10')
 */
const minLength = <const min extends number>(min: min) =>
  when((value) => isString(value) && value.length >= min);

/**
 * `P.string.length(len)` is a pattern, matching **strings** with exactly `len` characters.
 *
 * [Read the documentation for `P.string.length` on GitHub](https://github.com/gvergnaud/ts-pattern#pstringlength)
 *
 * @example
 *  match(value)
 *   .with(P.string.length(10), () => 'strings with length === 10')
 */
const length = <const len extends number>(len: len) =>
  when((value) => isString(value) && value.length === len);

/**
 * `P.string.maxLength(max)` is a pattern, matching **strings** with at most `max` characters.
 *
 * [Read the documentation for `P.string.maxLength` on GitHub](https://github.com/gvergnaud/ts-pattern#pstringmaxLength)
 *
 * @example
 *  match(value)
 *   .with(P.string.maxLength(10), () => 'string with more length <= 10')
 */
const maxLength = <const max extends number>(max: max) =>
  when((value) => isString(value) && value.length <= max);

/**
 * `P.string.includes(substr)` is a pattern, matching **strings** containing `substr`.
 *
 * [Read the documentation for `P.string.includes` on GitHub](https://github.com/gvergnaud/ts-pattern#pstringincludes)
 *
 * @example
 *  match(value)
 *   .with(P.string.includes('http'), () => 'value contains http')
 */
const includes = <input, const substr extends string>(
  substr: substr
): GuardExcludeP<input, string, never> =>
  when((value) => isString(value) && value.includes(substr));

/**
 * `P.string.regex(expr)` is a pattern, matching **strings** that `expr` regular expression.
 *
 * [Read the documentation for `P.string.regex` on GitHub](https://github.com/gvergnaud/ts-pattern#pstringregex)
 *
 * @example
 *  match(value)
 *   .with(P.string.regex(/^https?:\/\//), () => 'url')
 */
const regex = <input, const expr extends string | RegExp>(
  expr: expr
): GuardExcludeP<input, string, never> =>
  when((value) => isString(value) && Boolean(value.match(expr)));

const stringChainable = <pattern extends Matcher<any, any, any, any, any>>(
  pattern: pattern
): StringChainable<pattern> =>
  Object.assign(chainable(pattern), {
    startsWith: (str: string) =>
      stringChainable(intersection(pattern, startsWith(str))),
    endsWith: (str: string) =>
      stringChainable(intersection(pattern, endsWith(str))),
    minLength: (min: number) =>
      stringChainable(intersection(pattern, minLength(min))),
    length: (len: number) =>
      stringChainable(intersection(pattern, length(len))),
    maxLength: (max: number) =>
      stringChainable(intersection(pattern, maxLength(max))),
    includes: (str: string) =>
      stringChainable(intersection(pattern, includes(str))),
    regex: (str: string) => stringChainable(intersection(pattern, regex(str))),
  }) as any;

/**
 * `P.string` is a wildcard pattern, matching any **string**.
 *
 * [Read the documentation for `P.string` on GitHub](https://github.com/gvergnaud/ts-pattern#pstring-wildcard)
 *
 * @example
 *  match(value)
 *   .with(P.string, () => 'will match on strings')
 */
export const string: StringPattern = stringChainable(when(isString));

/**
 * `P.number.between(min, max)` matches **numbers** between `min` and `max`,
 * equal to min or equal to max.
 *
 * [Read the documentation for `P.number.between` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumberbetween)
 *
 * @example
 *  match(value)
 *   .with(P.number.between(0, 10), () => '0 <= numbers <= 10')
 */
const between = <input, const min extends number, const max extends number>(
  min: min,
  max: max
): GuardExcludeP<input, number, never> =>
  when((value) => isNumber(value) && min <= value && max >= value);

/**
 * `P.number.lt(max)` matches **numbers** smaller than `max`.
 *
 * [Read the documentation for `P.number.lt` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumberlt)
 *
 * @example
 *  match(value)
 *   .with(P.number.lt(10), () => 'numbers < 10')
 */
const lt = <input, const max extends number>(
  max: max
): GuardExcludeP<input, number, never> =>
  when((value) => isNumber(value) && value < max);

/**
 * `P.number.gt(min)` matches **numbers** greater than `min`.
 *
 * [Read the documentation for `P.number.gt` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumbergt)
 *
 * @example
 *  match(value)
 *   .with(P.number.gt(10), () => 'numbers > 10')
 */
const gt = <input, const min extends number>(
  min: min
): GuardExcludeP<input, number, never> =>
  when((value) => isNumber(value) && value > min);

/**
 * `P.number.lte(max)` matches **numbers** smaller than or equal to `max`.
 *
 * [Read the documentation for `P.number.lte` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumberlte)
 *
 * @example
 *  match(value)
 *   .with(P.number.lte(10), () => 'numbers <= 10')
 */
const lte = <input, const max extends number>(
  max: max
): GuardExcludeP<input, number, never> =>
  when((value) => isNumber(value) && value <= max);

/**
 * `P.number.gte(min)` matches **numbers** greater than or equal to `min`.
 *
 * [Read the documentation for `P.number.gte` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumbergte)
 *
 * @example
 *  match(value)
 *   .with(P.number.gte(10), () => 'numbers >= 10')
 */
const gte = <input, const min extends number>(
  min: min
): GuardExcludeP<input, number, never> =>
  when((value) => isNumber(value) && value >= min);

/**
 * `P.number.int()` matches **integer** numbers.
 *
 * [Read the documentation for `P.number.int()` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumberint)
 *
 * @example
 *  match(value)
 *   .with(P.number.int(), () => 'an integer')
 */
const int = <input>(): GuardExcludeP<input, number, never> =>
  when((value) => isNumber(value) && Number.isInteger(value));

/**
 * `P.number.finite` matches **finite numbers**.
 *
 * [Read the documentation for `P.number.finite` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumberfinite)
 *
 * @example
 *  match(value)
 *   .with(P.number.finite, () => 'not Infinity')
 */
const finite = <input>(): GuardExcludeP<input, number, never> =>
  when((value) => isNumber(value) && Number.isFinite(value));

/**
 * `P.number.positive()` matches **positive** numbers.
 *
 * [Read the documentation for `P.number.positive()` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumberpositive)
 *
 * @example
 *  match(value)
 *   .with(P.number.positive(), () => 'number > 0')
 */
const positive = <input>(): GuardExcludeP<input, number, never> =>
  when((value) => isNumber(value) && value > 0);

/**
 * `P.number.negative()` matches **negative** numbers.
 *
 * [Read the documentation for `P.number.negative()` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumbernegative)
 *
 * @example
 *  match(value)
 *   .with(P.number.negative(), () => 'number < 0')
 */
const negative = <input>(): GuardExcludeP<input, number, never> =>
  when((value) => isNumber(value) && value < 0);

const numberChainable = <pattern extends Matcher<any, any, any, any, any>>(
  pattern: pattern
): NumberChainable<pattern> =>
  Object.assign(chainable(pattern), {
    between: (min: number, max: number) =>
      numberChainable(intersection(pattern, between(min, max))),
    lt: (max: number) => numberChainable(intersection(pattern, lt(max))),
    gt: (min: number) => numberChainable(intersection(pattern, gt(min))),
    lte: (max: number) => numberChainable(intersection(pattern, lte(max))),
    gte: (min: number) => numberChainable(intersection(pattern, gte(min))),
    int: () => numberChainable(intersection(pattern, int())),
    finite: () => numberChainable(intersection(pattern, finite())),
    positive: () => numberChainable(intersection(pattern, positive())),
    negative: () => numberChainable(intersection(pattern, negative())),
  }) as any;

/**
 * `P.number` is a wildcard pattern, matching any **number**.
 *
 * [Read the documentation for `P.number` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumber-wildcard)
 *
 * @example
 *  match(value)
 *   .with(P.number, () => 'will match on numbers')
 */
export const number: NumberPattern = numberChainable(when(isNumber));

/**
 * `P.bigint.between(min, max)` matches **bigint** between `min` and `max`,
 * equal to min or equal to max.
 *
 * [Read the documentation for `P.bigint.between` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumberbetween)
 *
 * @example
 *  match(value)
 *   .with(P.bigint.between(0, 10), () => '0 <= bigints <= 10')
 */
const betweenBigInt = <
  input,
  const min extends bigint,
  const max extends bigint
>(
  min: min,
  max: max
): GuardExcludeP<input, bigint, never> =>
  when((value) => isBigInt(value) && min <= value && max >= value);

/**
 * `P.bigint.lt(max)` matches **bigint** smaller than `max`.
 *
 * [Read the documentation for `P.bigint.lt` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumberlt)
 *
 * @example
 *  match(value)
 *   .with(P.bigint.lt(10), () => 'bigints < 10')
 */
const ltBigInt = <input, const max extends bigint>(
  max: max
): GuardExcludeP<input, bigint, never> =>
  when((value) => isBigInt(value) && value < max);

/**
 * `P.bigint.gt(min)` matches **bigint** greater than `min`.
 *
 * [Read the documentation for `P.bigint.gt` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumbergt)
 *
 * @example
 *  match(value)
 *   .with(P.bigint.gt(10), () => 'bigints > 10')
 */
const gtBigInt = <input, const min extends bigint>(
  min: min
): GuardExcludeP<input, bigint, never> =>
  when((value) => isBigInt(value) && value > min);

/**
 * `P.bigint.lte(max)` matches **bigint** smaller than or equal to `max`.
 *
 * [Read the documentation for `P.bigint.lte` on GitHub](https://github.com/gvergnaud/ts-pattern#pnumberlte)
 *
 * @example
 *  match(value)
 *   .with(P.bigint.lte(10), () => 'bigints <= 10')
 */
const lteBigInt = <input, const max extends bigint>(
  max: max
): GuardExcludeP<input, bigint, never> =>
  when((value) => isBigInt(value) && value <= max);

/**
 * `P.bigint.gte(min)` matches **bigint** greater than or equal to `min`.
 *
 * [Read the documentation for `P.bigint.gte` on GitHub](https://github.com/gvergnaud/ts-pattern#pbigintgte)
 *
 * @example
 *  match(value)
 *   .with(P.bigint.gte(10), () => 'bigints >= 10')
 */
const gteBigInt = <input, const min extends bigint>(
  min: min
): GuardExcludeP<input, bigint, never> =>
  when((value) => isBigInt(value) && value >= min);

/**
 * `P.bigint.positive()` matches **positive** bigints.
 *
 * [Read the documentation for `P.bigint.positive()` on GitHub](https://github.com/gvergnaud/ts-pattern#pbigintpositive)
 *
 * @example
 *  match(value)
 *   .with(P.bigint.positive(), () => 'bigint > 0')
 */
const positiveBigInt = <input>(): GuardExcludeP<input, bigint, never> =>
  when((value) => isBigInt(value) && value > 0);

/**
 * `P.bigint.negative()` matches **negative** bigints.
 *
 * [Read the documentation for `P.bigint.negative()` on GitHub](https://github.com/gvergnaud/ts-pattern#pbigintnegative)
 *
 * @example
 *  match(value)
 *   .with(P.bigint.negative(), () => 'bigint < 0')
 */
const negativeBigInt = <input>(): GuardExcludeP<input, bigint, never> =>
  when((value) => isBigInt(value) && value < 0);

const bigintChainable = <pattern extends Matcher<any, any, any, any, any>>(
  pattern: pattern
): BigIntChainable<pattern> =>
  Object.assign(chainable(pattern), {
    between: (min: bigint, max: bigint) =>
      bigintChainable(intersection(pattern, betweenBigInt(min, max))),
    lt: (max: bigint) => bigintChainable(intersection(pattern, ltBigInt(max))),
    gt: (min: bigint) => bigintChainable(intersection(pattern, gtBigInt(min))),
    lte: (max: bigint) =>
      bigintChainable(intersection(pattern, lteBigInt(max))),
    gte: (min: bigint) =>
      bigintChainable(intersection(pattern, gteBigInt(min))),
    positive: () => bigintChainable(intersection(pattern, positiveBigInt())),
    negative: () => bigintChainable(intersection(pattern, negativeBigInt())),
  }) as any;

/**
 * `P.bigint` is a wildcard pattern, matching any **bigint**.
 *
 * [Read the documentation for `P.bigint` on GitHub](https://github.com/gvergnaud/ts-pattern#number-wildcard)
 *
 * @example
 *   .with(P.bigint, () => 'will match on bigints')
 */
export const bigint: BigIntPattern = bigintChainable(when(isBigInt));

/**
 * `P.boolean` is a wildcard pattern, matching any **boolean**.
 *
 * [Read the documentation for `P.boolean` on GitHub](https://github.com/gvergnaud/ts-pattern#boolean-wildcard)
 *
 * @example
 *   .with(P.boolean, () => 'will match on booleans')
 */
export const boolean: BooleanPattern = chainable(when(isBoolean));

/**
 * `P.symbol` is a wildcard pattern, matching any **symbol**.
 *
 * [Read the documentation for `P.symbol` on GitHub](https://github.com/gvergnaud/ts-pattern#symbol-wildcard)
 *
 * @example
 *   .with(P.symbol, () => 'will match on symbols')
 */
export const symbol: SymbolPattern = chainable(when(isSymbol));

/**
 * `P.nullish` is a wildcard pattern, matching **null** or **undefined**.
 *
 * [Read the documentation for `P.nullish` on GitHub](https://github.com/gvergnaud/ts-pattern#nullish-wildcard)
 *
 * @example
 *   .with(P.nullish, (x) => `${x} is null or undefined`)
 */
export const nullish: NullishPattern = chainable(when(isNullish));

/**
 * `P.nonNullable` is a wildcard pattern, matching everything except **null** or **undefined**.
 *
 * [Read the documentation for `P.nonNullable` on GitHub](https://github.com/gvergnaud/ts-pattern#nonNullable-wildcard)
 *
 * @example
 *   .with(P.nonNullable, (x) => `${x} isn't null nor undefined`)
 */
export const nonNullable: NonNullablePattern = chainable(when(isNonNullable));

/**
 * `P.instanceOf(SomeClass)` is a pattern matching instances of a given class.
 *
 * [Read the documentation for `P.instanceOf` on GitHub](https://github.com/gvergnaud/ts-pattern#pinstanceof-patterns)
 *
 *  @example
 *   .with(P.instanceOf(SomeClass), () => 'will match on SomeClass instances')
 */
export function instanceOf<T extends AnyConstructor>(
  classConstructor: T
): Chainable<GuardP<unknown, InstanceType<T>>> {
  return chainable(when(isInstanceOf(classConstructor)));
}

/**
 * `P.shape(somePattern)` lets you call methods like `.optional()`, `.and`, `.or` and `.select()`
 * On structural patterns, like objects and arrays.
 *
 * [Read the documentation for `P.shape` on GitHub](https://github.com/gvergnaud/ts-pattern#pshape-patterns)
 *
 *  @example
 *   .with(
 *     {
 *       state: P.shape({ status: "success" }).optional().select()
 *     },
 *     (state) => 'match the success state, or undefined.'
 *   )
 */
export function shape<input, const pattern extends Pattern<input>>(
  pattern: pattern
): Chainable<GuardP<input, InvertPattern<pattern, input>>>;
export function shape(pattern: UnknownValuePattern) {
  return chainable(when(isMatching(pattern)));
}


================================================
FILE: src/types/BuildMany.ts
================================================
import { Iterator, IsOptionalKeysOf, UpdateAt, ValueOf } from './helpers';

// BuildMany :: DataStructure -> Union<[value, path][]> -> Union<DataStructure>
export type BuildMany<data, xs extends readonly any[]> = xs extends any
  ? BuildOne<data, xs>
  : never;

// BuildOne :: DataStructure
// -> [value, path][]
// -> DataStructure
type BuildOne<data, xs extends readonly any[]> = xs extends [
  [infer value, infer path],
  ...infer tail
]
  ? BuildOne<SetDeep<data, value, path>, tail>
  : data;

// SetDeep :: a -> b -> PropertyKey[] -> a
export type SetDeep<data, value, path> = path extends readonly [
  infer head,
  ...infer tail
]
  ? data extends readonly any[]
    ? data extends readonly [any, ...any]
      ? head extends number
        ? UpdateAt<data, Iterator<head>, SetDeep<data[head], value, tail>>
        : never
      : SetDeep<ValueOf<data>, value, tail>[]
    : data extends Set<infer a>
    ? Set<SetDeep<a, value, tail>>
    : data extends Map<infer k, infer v>
    ? Map<k, SetDeep<v, value, tail>>
    : head extends keyof data
    ? // if we intentionally set undefined on an optional key, we should keep
      // the optional modifier, otherwise it will exclude the `undefined` type from
      // our `value` type.
      [IsOptionalKeysOf<data, head>, tail, undefined] extends [true, [], value]
      ? { [k in keyof data]: k extends head ? value : data[k] }
      : {
          [k in keyof data]-?: k extends head
            ? SetDeep<data[head], value, tail>
            : data[k];
        }
    : data
  : value;


================================================
FILE: src/types/DeepExclude.ts
================================================
import { DistributeMatchingUnions } from './DistributeUnions';

export type DeepExclude<a, b> = Exclude<DistributeMatchingUnions<a, b>, b>;


================================================
FILE: src/types/DistributeUnions.ts
================================================
import { BuildMany } from './BuildMany';
import type {
  IsAny,
  Values,
  Flatten,
  IsUnion,
  IsPlainObject,
  Length,
  UnionToTuple,
  IsReadonlyArray,
  ValueOf,
  MaybeAddReadonly,
  IsStrictArray,
} from './helpers';
import { IsMatching } from './IsMatching';

/**
 * DistributeMatchingUnions takes two arguments:
 * - a data structure of type `a` containing unions
 * - a pattern `p`, matching this data structure
 * and turns it into a union of all possible
 * combination of each unions contained in `a` that matches `p`.
 *
 * It does this in 3 main steps:
 *  - 1. Find all unions contained in the data structure, that matches `p`
 *    with `FindUnions<a, p>`. It returns a tree of [union, path] pairs.
 *  - 2. this tree is passed to the `Distribute` type level function,
 *    Which turns it into a union of list of `[singleValue, path]` pairs.
 *    Each list correspond to one of the possible combination of the unions
 *    found in `a`.
 *  - 3. build a data structure with the same shape as `a` for each combination
 *    and return the union of these data structures.
 *
 * @example
 * type t1 = DistributeMatchingUnions<['a' | 'b', 1 | 2], ['a', 1]>;
 * // => ['a', 1] | ['a', 2] | ['b', 1] | ['b', 2]
 *
 * type t2 = DistributeMatchingUnions<['a' | 'b', 1 | 2], ['a', unknown]>;
 * // => ['a', 1 | 2] | ['b', 1 | 2]
 */
export type DistributeMatchingUnions<a, p> = IsAny<a> extends true
  ? any
  : BuildMany<a, Distribute<FindUnionsMany<a, p>>>;

// FindUnionsMany :: a -> Union<a> -> PropertyKey[] -> UnionConfig[]
export type FindUnionsMany<
  a,
  p,
  path extends PropertyKey[] = []
> = UnionToTuple<
  (
    p extends any
      ? IsMatching<a, p> extends true
        ? FindUnions<a, p, path>
        : []
      : never
  ) extends readonly (infer T)[]
    ? T
    : never
>;

/**
 * The reason we don't look further down the tree with lists,
 * Set and Maps is that they can be heterogeneous,
 * so matching on a A[] for a in input of (A|B)[]
 * doesn't rule anything out. You can still have
 * a (A|B)[] afterward. The same logic goes for Set and Maps.
 *
 * Kinds are types of types.
 *
 * kind UnionConfig = {
 *  cases: Union<{
 *    value: b,
 *    subUnions: UnionConfig[]
 *  }>,
 *  path: string[]
 * }
 * FindUnions :: Pattern a p => a -> p -> UnionConfig[]
 */
export type FindUnions<
  a,
  p,
  path extends PropertyKey[] = []
> = unknown extends p
  ? []
  : IsAny<p> extends true
  ? [] // Don't try to find unions after 5 levels
  : Length<path> extends 5
  ? []
  : IsUnion<a> extends true
  ? [
      {
        cases: a extends any
          ? {
              value: a;
              subUnions: FindUnionsMany<a, p, path>;
            }
          : never;
        path: path;
      }
    ]
  : [a, p] extends [readonly any[], readonly any[]]
  ? [a, p] extends [
      readonly [infer a1, infer a2, infer a3, infer a4, infer a5],
      readonly [infer p1, infer p2, infer p3, infer p4, infer p5]
    ]
    ? [
        ...FindUnions<a1, p1, [...path, 0]>,
        ...FindUnions<a2, p2, [...path, 1]>,
        ...FindUnions<a3, p3, [...path, 2]>,
        ...FindUnions<a4, p4, [...path, 3]>,
        ...FindUnions<a5, p5, [...path, 4]>
      ]
    : [a, p] extends [
        readonly [infer a1, infer a2, infer a3, infer a4],
        readonly [infer p1, infer p2, infer p3, infer p4]
      ]
    ? [
        ...FindUnions<a1, p1, [...path, 0]>,
        ...FindUnions<a2, p2, [...path, 1]>,
        ...FindUnions<a3, p3, [...path, 2]>,
        ...FindUnions<a4, p4, [...path, 3]>
      ]
    : [a, p] extends [
        readonly [infer a1, infer a2, infer a3],
        readonly [infer p1, infer p2, infer p3]
      ]
    ? [
        ...FindUnions<a1, p1, [...path, 0]>,
        ...FindUnions<a2, p2, [...path, 1]>,
        ...FindUnions<a3, p3, [...path, 2]>
      ]
    : [a, p] extends [
        readonly [infer a1, infer a2],
        readonly [infer p1, infer p2]
      ]
    ? [...FindUnions<a1, p1, [...path, 0]>, ...FindUnions<a2, p2, [...path, 1]>]
    : [a, p] extends [readonly [infer a1], readonly [infer p1]]
    ? FindUnions<a1, p1, [...path, 0]>
    : /**
     * Special case when matching with a variadic tuple on a regular array.
     * in this case we turn the input array `A[]` into `[] | [A, ...A[]]`
     * to remove one of these cases during DeepExclude.
     */
    p extends readonly [] | readonly [any, ...any] | readonly [...any, any]
    ? IsStrictArray<Extract<a, readonly any[]>> extends false
      ? []
      : [
          ArrayToVariadicUnion<a, p> extends infer aUnion
            ? {
                cases: aUnion extends any
                  ? {
                      value: aUnion;
                      subUnions: [];
                    }
                  : never;
                path: path;
              }
            : never
        ]
    : []
  : a extends Set<any>
  ? []
  : a extends Map<any, any>
  ? []
  : [IsPlainObject<a>, IsPlainObject<p>] extends [true, true]
  ? Flatten<
      Values<{
        [k in keyof a & keyof p]: FindUnions<a[k], p[k], [...path, k]>;
      }>
    >
  : [];

export type ArrayToVariadicUnion<input, excluded> = MaybeAddReadonly<
  | (input extends readonly [any, ...any] | readonly [...any, any] ? never : [])
  | (excluded extends readonly [...any, any]
      ? [...Extract<input, readonly any[]>, ValueOf<input>]
      : [ValueOf<input>, ...Extract<input, readonly any[]>]),
  IsReadonlyArray<input>
>;

// Distribute :: UnionConfig[] -> Union<[a, path][]>
export type Distribute<unions extends readonly any[]> =
  unions extends readonly [
    { cases: infer cases; path: infer path },
    ...infer tail
  ]
    ? cases extends { value: infer value; subUnions: infer subUnions }
      ? [
          [value, path],
          ...Distribute<Extract<subUnions, readonly any[]>>,
          ...Distribute<tail>
        ]
      : never
    : [];


================================================
FILE: src/types/ExtractPreciseValue.ts
================================================
import type { Override } from './Pattern';
import type {
  BuiltInObjects,
  Compute,
  Contains,
  IsPlainObject,
  IsReadonlyArray,
  LeastUpperBound,
  MaybeAddReadonly,
  ValueOf,
} from './helpers';

export type ExtractPreciseValue<a, b> = b extends Override<infer b1>
  ? b1
  : unknown extends b
  ? a
  : // inlining IsAny for perf
  0 extends 1 & b
  ? a
  : // inlining IsAny for perf
  0 extends 1 & a
  ? b
  : b extends readonly any[]
  ? ExtractPreciseArrayValue<a, b, IsReadonlyArray<a>>
  : b extends Map<infer bk, infer bv>
  ? a extends Map<infer ak, infer av>
    ? Map<ExtractPreciseValue<ak, bk>, ExtractPreciseValue<av, bv>>
    : LeastUpperBound<a, b>
  : b extends Set<infer bv>
  ? a extends Set<infer av>
    ? Set<ExtractPreciseValue<av, bv>>
    : LeastUpperBound<a, b>
  : // We add `Error` to the excludeUnion because
  // We want to consider them like primitive values in this context.
  IsPlainObject<b, BuiltInObjects | Error> extends true
  ? a extends object
    ? a extends b
      ? a
      : b extends a
      ? Contains<b, never> extends true
        ? never
        : // An empty object `{}` in a pattern means
        // that this key must be non-nullable.
        // If we find a key in `b` that doesn't exist in `a`
        // and that contains `{}`, then the pattern does not match.
        Contains<Omit<b, keyof a>, {}> extends true
        ? never
        : // If values have no keys in common, return `b`
        [Exclude<keyof a, keyof b>] extends [never]
        ? b
        : // Otherwise return `b` with keys of `a`
          // that do not exist on `b`.
          // It can only be optional properties,
          // otherwise `b extends a` wouldn't
          // not have passed.
          Compute<b & Omit<a, keyof b>>
      : [keyof a & keyof b] extends [never]
      ? never
      : Compute<
          // Keep other properties of `a`
          {
            // `in keyof a as ...` preserves property modifiers,
            // unlike `in keyof Exclude<keyof a, keyof b>`.
            [k in keyof a as k extends keyof b ? never : k]: a[k];
          } & {
            // use `b` to extract precise values on `a`.
            // This has the effect of preserving the optional
            // property modifier (?:) of b in the output type.
            [k in keyof b]: k extends keyof a
              ? ExtractPreciseValue<a[k], b[k]>
              : b[k];
          }
        > extends infer result
      ? Contains<Pick<result, keyof result & keyof b>, never> extends true
        ? never
        : result
      : never
    : LeastUpperBound<a, b>
  : LeastUpperBound<a, b>;

type ExtractPreciseArrayValue<
  a,
  b,
  isReadonly extends boolean,
  startOutput extends any[] = [],
  endOutput extends any[] = []
> = a extends readonly (infer aItem)[]
  ? b extends readonly []
    ? MaybeAddReadonly<[...startOutput, ...endOutput], isReadonly>
    : b extends readonly [infer b1, ...infer bRest]
    ? a extends readonly [infer a1, ...infer aRest]
      ? ExtractPreciseValue<a1, b1> extends infer currentValue
        ? [currentValue] extends [never]
          ? never
          : ExtractPreciseArrayValue<
              aRest,
              bRest,
              isReadonly,
              [...startOutput, currentValue],
              endOutput
            >
        : never
      : ExtractPreciseValue<aItem, b1> extends infer currentValue
      ? [currentValue] extends [never]
        ? never
        : ExtractPreciseArrayValue<
            aItem[],
            bRest,
            isReadonly,
            [...startOutput, currentValue],
            endOutput
          >
      : never
    : b extends readonly [...infer bInit, infer b1]
    ? a extends readonly [...infer aInit, infer a1]
      ? ExtractPreciseValue<a1, b1> extends infer currentValue
        ? [currentValue] extends [never]
          ? never
          : ExtractPreciseArrayValue<
              aInit,
              bInit,
              isReadonly,
              startOutput,
              [...endOutput, currentValue]
            >
        : never
      : ExtractPreciseValue<aItem, b1> extends infer currentValue
      ? [currentValue] extends [never]
        ? never
        : ExtractPreciseArrayValue<
            aItem[],
            bInit,
            isReadonly,
            startOutput,
            [...endOutput, currentValue]
          >
      : never
    : ExtractPreciseValue<aItem, ValueOf<b>> extends infer currentValue
    ? [currentValue] extends [never]
      ? never
      : MaybeAddReadonly<
          [...startOutput, ...currentValue[], ...endOutput],
          isReadonly
        >
    : never
  : LeastUpperBound<a, b>;


================================================
FILE: src/types/FindSelected.ts
================================================
import type * as symbols from '../internals/symbols';
import type { AnyMatcher, Matcher, Pattern } from './Pattern';
import type {
  Equal,
  Primitives,
  ValueOf,
  MergeUnion,
  IsUnion,
} from './helpers';

type SelectionsRecord = Record<string, [unknown, unknown[]]>;

export type None = {
  type: 'none';
};
export type Some<key extends string> = {
  type: 'some';
  key: key;
};

export type SelectionType = None | Some<string>;

// SelectionsRecord -> SelectionsRecord
type MapOptional<selections> = {
  [k in keyof selections]: selections[k] extends [infer v, infer subpath]
    ? [v | undefined, subpath]
    : never;
};

// SelectionsRecord -> SelectionsRecord
type MapList<selections> = {
  [k in keyof selections]: selections[k] extends [infer v, infer subpath]
    ? [v[], subpath]
    : never;
};

// input -> pattern[] -> (string | number)[] -> Union SelectionRecord
type ReduceFindSelectionUnion<
  i,
  ps extends readonly any[],
  output = never
> = ps extends readonly [infer head, ...infer tail]
  ? ReduceFindSelectionUnion<i, tail, output | FindSelectionUnion<i, head>>
  : output;

// input -> pattern -> (string | number)[] -> Union SelectionRecord
type FindSelectionUnionInArray<
  i,
  p,
  path extends any[] = [],
  output = never
> = i extends readonly (infer iItem)[]
  ? p extends readonly []
    ? output
    : p extends readonly [infer p1, ...infer pRest]
    ? i extends readonly [infer i1, ...infer iRest]
      ? FindSelectionUnionInArray<
          iRest,
          pRest,
          [...path, p['length']],
          output | FindSelectionUnion<i1, p1, [...path, p['length']]>
        >
      : FindSelectionUnionInArray<
          iItem[],
          pRest,
          [...path, p['length']],
          output | FindSelectionUnion<iItem, p1, [...path, p['length']]>
        >
    : p extends readonly [...infer pInit, infer p1]
    ? i extends readonly [...infer iInit, infer i1]
      ? FindSelectionUnionInArray<
          iInit,
          pInit,
          [...path, p['length']],
          output | FindSelectionUnion<i1, p1, [...path, p['length']]>
        >
      : FindSelectionUnionInArray<
          iItem[],
          pInit,
          [...path, p['length']],
          output | FindSelectionUnion<iItem, p1, [...path, p['length']]>
        >
    : // If P is a matcher, in this case, it's likely an array matcher
    p extends readonly [...(readonly (infer pRest & AnyMatcher)[])]
    ? output | FindSelectionUnion<i, pRest, [...path, p['length']]>
    :
        | output
        | FindSelectionUnion<
            iItem,
            ValueOf<p>,
            [...path, Extract<p, readonly any[]>['length']]
          >
  : output;

// input -> pattern -> (string | number)[] -> SelectionsRecord
export type FindSelectionUnion<
  i,
  p,
  // path just serves as an id, to identify different anonymous patterns which have the same type
  path extends any[] = []
  // inlining IsAny for perf
> = 0 extends 1 & i
  ? never
  : // inlining IsAny for perf
  0 extends 1 & p
  ? never
  : p extends Primitives
  ? never
  : p extends Matcher<any, infer pattern, infer matcherType, infer sel>
  ? {
      select: sel extends Some<infer k>
        ? { [kk in k]: [i, path] } | FindSelectionUnion<i, pattern, path>
        : never;
      // selection of arrays, records, maps, and sets are arrays,
      // because the selection function is being mapped on their values
      array: i extends readonly (infer iItem)[]
        ? MapList<FindSelectionUnion<iItem, pattern>>
        : never;
      record: [i, pattern] extends [
        Record<infer k, infer v>,
        [infer pkey, infer pvalue]
      ]
        ?
            | MapList<FindSelectionUnion<k, pkey, path>>
            | MapList<FindSelectionUnion<v, pvalue, path>>
        : never;
      map: [i, pattern] extends [
        Map<infer k, infer v>,
        [infer pkey, infer pvalue]
      ]
        ?
            | MapList<FindSelectionUnion<k, pkey, path>>
            | MapList<FindSelectionUnion<v, pvalue, path>>
        : never;
      set: i extends Set<infer v>
        ? MapList<FindSelectionUnion<v, pattern, path>>
        : never;
      optional: MapOptional<FindSelectionUnion<i, pattern>>;
      or: MapOptional<
        ReduceFindSelectionUnion<i, Extract<pattern, readonly any[]>>
      >;
      and: ReduceFindSelectionUnion<i, Extract<pattern, readonly any[]>>;
      not: never;
      default: sel extends Some<infer k> ? { [kk in k]: [i, path] } : never;
      custom: never;
    }[matcherType]
  : p extends readonly any[]
  ? FindSelectionUnionInArray<i, p>
  : p extends {}
  ? i extends {}
    ? {
        [k in keyof p]: k extends keyof i
          ? FindSelectionUnion<i[k], p[k], [...path, k]>
          : never;
      }[keyof p]
    : never
  : never;

export type SeveralAnonymousSelectError<
  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'
> = {
  __error: never;
} & a;

export type MixedNamedAndAnonymousSelectError<
  a = 'Mixing named selections (`select("name")`) and anonymous selections (`select()`) is forbiden. Please, only use named selections.'
> = {
  __error: never;
} & a;

//                       Multiple selections   Single selection
//                                 👇               👇
// SelectionsRecord -> Record<string, unknown> | unknown | Error
export type SelectionToArgs<selections extends SelectionsRecord> =
  symbols.anonymousSelectKey extends keyof selections
    ? // if there are several different paths for anonymous selections
      // it means that P.select() has been used more than once.
      IsUnion<selections[symbols.anonymousSelectKey][1]> extends true
      ? SeveralAnonymousSelectError
      : keyof selections extends symbols.anonymousSelectKey
      ? selections[symbols.anonymousSelectKey][0]
      : MixedNamedAndAnonymousSelectError
    : { [k in keyof selections]: selections[k][0] };

export type Selections<i, p> = FindSelectionUnion<i, p> extends infer u
  ? [u] extends [never]
    ? i
    : SelectionToArgs<Extract<MergeUnion<u>, SelectionsRecord>>
  : i;

export type FindSelected<i, p> =
  // This happens if the provided pattern didn't extend Pattern<i>,
  // Because the type checker falls back on the general `Pattern<i>` type
  // in this case.
  Equal<p, Pattern<i>> extends true ? i : Selections<i, p>;


================================================
FILE: src/types/InvertPattern.ts
================================================
import { DeepExclude } from './DeepExclude';
import {
  IsPlainObject,
  Primitives,
  IsLiteral,
  ValueOf,
  Compute,
  Equal,
  Extends,
  Not,
  All,
  NonLiteralPrimitive,
  MaybeAddReadonly,
  IsReadonlyArray,
  MapKey,
  MapValue,
  SetValue,
  ExtractPlainObject,
  GetKey,
  Call,
  Fn,
  ReadonlyArrayValue,
  WithDefault,
  RecordKey,
  RecordValue,
} from './helpers';
import type { Matcher, Pattern, Override, AnyMatcher } from './Pattern';

type OptionalKeys<p> = ValueOf<{
  [k in keyof p]: 0 extends 1 & p[k] // inlining IsAny for perf
    ? never
    : p[k] extends Matcher<any, any, infer matcherType>
    ? matcherType extends 'optional'
      ? k
      : never
    : never;
}>;

type ReduceUnion<
  tuple extends readonly any[],
  i,
  output = never
> = tuple extends readonly [infer p, ...infer tail]
  ? ReduceUnion<tail, i, output | InvertPatternInternal<p, i>>
  : output;

type ReduceIntersection<
  tuple extends readonly any[],
  i,
  output = unknown
> = tuple extends readonly [infer p, ...infer tail]
  ? ReduceIntersection<tail, i, output & InvertPatternInternal<p, i>>
  : output;

type InvertArrayPattern<
  p,
  i,
  startOutput extends any[] = [],
  endOutput extends any[] = []
> = i extends readonly (infer ii)[]
  ? p extends readonly []
    ? [...startOutput, ...endOutput]
    : p extends readonly [infer p1, ...infer pRest]
    ? i extends readonly [infer i1, ...infer iRest]
      ? InvertArrayPattern<
          pRest,
          iRest,
          [...startOutput, InvertPatternInternal<p1, i1>],
          endOutput
        >
      : InvertArrayPattern<
          pRest,
          ii[],
          [...startOutput, InvertPatternInternal<p1, ii>],
          endOutput
        >
    : p extends readonly [...infer pInit, infer p1]
    ? i extends readonly [...infer iInit, infer i1]
      ? InvertArrayPattern<
          pInit,
          iInit,
          startOutput,
          [...endOutput, InvertPatternInternal<p1, i1>]
        >
      : InvertArrayPattern<
          pInit,
          ii[],
          startOutput,
          [...endOutput, InvertPatternInternal<p1, ii>]
        >
    : // If P is a matcher, in this case, it's likely an array matcher
    p extends readonly [...(readonly (infer pRest & AnyMatcher)[])]
    ? [
        ...startOutput,
        ...Extract<InvertPatternInternal<pRest, i>, readonly any[]>,
        ...endOutput
      ]
    : [...startOutput, ...InvertPatternInternal<ValueOf<p>, ii>[], ...endOutput]
  : never;

/**
 * ### InvertPatternInternal
 * Since patterns have special wildcard values, we need a way
 * to transform a pattern into the type of value it represents
 */
export type InvertPattern<p, input> = Equal<Pattern<input>, p> extends true
  ? never
  : InvertPatternInternal<p, input>;

type InvertPatternInternal<p, input> = 0 extends 1 & p
  ? never
  : p extends Matcher<
      infer _input,
      infer subpattern,
      infer matcherType,
      any,
      infer narrowedOrFn
    >
  ? {
      not: DeepExclude<input, InvertPatternInternal<subpattern, input>>;
      select: InvertPatternInternal<subpattern, input>;
      array: InvertPatternInternal<subpattern, ReadonlyArrayValue<input>>[];
      record: subpattern extends [infer pk, infer pv]
        ? Record<
            Extract<InvertPatternInternal<pk, RecordKey<input>>, PropertyKey>,
            InvertPatternInternal<pv, RecordValue<input>>
          >
        : never;
      map: subpattern extends [infer pk, infer pv]
        ? Map<
            InvertPatternInternal<pk, MapKey<Extract<input, Map<any, any>>>>,
            InvertPatternInternal<pv, MapValue<Extract<input, Map<any, any>>>>
          >
        : never;
      set: Set<
        InvertPatternInternal<subpattern, SetValue<Extract<input, Set<any>>>>
      >;
      optional:
        | InvertPatternInternal<subpattern, Exclude<input, undefined>>
        | undefined;
      and: ReduceIntersection<Extract<subpattern, readonly any[]>, input>;
      or: ReduceUnion<Extract<subpattern, readonly any[]>, input>;
      default: [subpattern] extends [never] ? input : subpattern;
      custom: Override<
        narrowedOrFn extends Fn ? Call<narrowedOrFn, input> : narrowedOrFn
      >;
    }[matcherType]
  : p extends Primitives
  ? p
  : p extends readonly any[]
  ? InvertArrayPattern<
      p,
      WithDefault<Extract<input, readonly any[]>, unknown[]>
    >
  : IsPlainObject<p> extends true
  ? OptionalKeys<p> extends infer optKeys
    ? [optKeys] extends [never]
      ? {
          [k in Exclude<keyof p, optKeys>]: InvertPatternInternal<
            p[k],
            WithDefault<GetKey<ExtractPlainObject<input>, k>, unknown>
          >;
        }
      : Compute<
          {
            [k in Exclude<keyof p, optKeys>]: InvertPatternInternal<
              p[k],
              WithDefault<GetKey<ExtractPlainObject<input>, k>, unknown>
            >;
          } & {
            [k in Extract<optKeys, keyof p>]?: InvertPatternInternal<
              p[k],
              WithDefault<GetKey<ExtractPlainObject<input>, k>, unknown>
            >;
          }
        >
    : never
  : p;

export type ReduceIntersectionForExclude<
  tuple extends readonly any[],
  i,
  output = unknown
> = tuple extends readonly [infer p, ...infer tail]
  ? ReduceIntersectionForExclude<
      tail,
      i,
      output & InvertPatternForExcludeInternal<p, i, unknown>
    >
  : output;

export type ReduceUnionForExclude<
  tuple extends readonly any[],
  i,
  output = never
> = tuple extends readonly [infer p, ...infer tail]
  ? ReduceUnionForExclude<
      tail,
      i,
      output | InvertPatternForExcludeInternal<p, i, never>
    >
  : output;

type ExcludeIfExists<a, b> =
  // If b is of type never, it probably means that P.not
  // was called with a `P.when` that wasn't a type guard function.
  // in this case we do not exclude
  [b] extends [never]
    ? never
    : // If a is unknown, we can't exclude
    // (Unless negative types are added in the future)
    unknown extends a
    ? never
    : All<
        [
          // if `a` is one of the non-literal primitive
          Extends<a, NonLiteralPrimitive>,
          Not<IsLiteral<a>>,
          // and b is a literal
          IsLiteral<b>
        ]
      > extends true
    ? // we shouldn't exclude because this will result in
      // excluding the whole primitive type even though only
      // one value has been handled by this pattern.
      // In other words `P.not(10)` on a `number` input shouldn't
      // exclude `number`.
      never
    : DeepExclude<a, b>;

type InvertArrayPatternForExclude<
  p,
  i,
  empty,
  isReadonly extends boolean,
  startOutput extends any[] = [],
  endOutput extends any[] = []
> = i extends readonly (infer ii)[]
  ? p extends readonly []
    ? MaybeAddReadonly<[...startOutput, ...endOutput], isReadonly>
    : p extends readonly [infer p1, ...infer pRest]
    ? i extends readonly [infer i1, ...infer iRest]
      ? InvertArrayPatternForExclude<
          pRest,
          iRest,
          empty,
          isReadonly,
          [...startOutput, InvertPatternForExcludeInternal<p1, i1, empty>],
          endOutput
        >
      : InvertArrayPatternForExclude<
          pRest,
          ii[],
          empty,
          isReadonly,
          [...startOutput, InvertPatternForExcludeInternal<p1, ii, empty>],
          endOutput
        >
    : p extends readonly [...infer pInit, infer p1]
    ? i extends readonly [...infer iInit, infer i1]
      ? InvertArrayPatternForExclude<
          pInit,
          iInit,
          empty,
          isReadonly,
          startOutput,
          [...endOutput, InvertPatternForExcludeInternal<p1, i1, empty>]
        >
      : InvertArrayPatternForExclude<
          pInit,
          ii[],
          empty,
          isReadonly,
          startOutput,
          [...endOutput, InvertPatternForExcludeInternal<p1, ii, empty>]
        >
    : // If P is a matcher, in this case, it's likely an array matcher
    p extends readonly [...(readonly (infer pRest & AnyMatcher)[])]
    ? MaybeAddReadonly<
        [
          ...startOutput,
          ...Extract<
            InvertPatternForExcludeInternal<pRest, i, empty>,
            readonly any[]
          >,
          ...endOutput
        ],
        isReadonly
      >
    : MaybeAddReadonly<
        [
          ...startOutput,
          ...InvertPatternForExcludeInternal<ValueOf<p>, ii, empty>[],
          ...endOutput
        ],
        isReadonly
      >
  : empty;

/**
 * ### InvertPatternForExclude
 */
export type InvertPatternForExclude<p, i> = Equal<Pattern<i>, p> extends true
  ? never
  : InvertPatternForExcludeInternal<p, i>;

type InvertPatternForExcludeInternal<p, i, empty = never> =
  // We need to prevent distribution because the boolean
  // type is a union of literal as well as a Primitive type
  // and it will end up being a false positif if we distribute it.
  unknown extends p
    ? i
    : [p] extends [Primitives]
    ? IsLiteral<p> extends true
      ? p
      : IsLiteral<i> extends true
      ? p
      : empty
    : p extends Matcher<
        infer matchableInput,
        infer subpattern,
        infer matcherType,
        any,
        infer excluded
      >
    ? {
        select: InvertPatternForExcludeInternal<subpattern, i, empty>;
        array: i extends readonly (infer ii)[]
          ? MaybeAddReadonly<
              InvertPatternForExcludeInternal<subpattern, ii, empty>[],
              IsReadonlyArray<i>
            >
          : empty;
        record: subpattern extends [infer pk, infer pv]
          ? Record<
              Extract<
                InvertPatternForExcludeInternal<pk, RecordKey<i>, empty>,
                PropertyKey
              >,
              InvertPatternForExcludeInternal<pv, RecordValue<i>, empty>
            >
          : empty;
        map: subpattern extends [infer pk, infer pv]
          ? i extends Map<infer ik, infer iv>
            ? Map<
                InvertPatternForExcludeInternal<pk, ik, empty>,
                InvertPatternForExcludeInternal<pv, iv, empty>
              >
            : empty
          : empty;
        set: i extends Set<infer iv>
          ? Set<InvertPatternForExcludeInternal<subpattern, iv, empty>>
          : empty;
        optional:
          | InvertPatternForExcludeInternal<subpattern, i, empty>
          | undefined;
        and: ReduceIntersectionForExclude<
          Extract<subpattern, readonly any[]>,
          i
        >;
        or: ReduceUnionForExclude<Extract<subpattern, readonly any[]>, i>;
        not: ExcludeIfExists<
          // we use matchableInput if possible because it represent the
          // union of all possible value, but i is only one of these values.
          unknown extends matchableInput ? i : matchableInput,
          InvertPatternForExcludeInternal<subpattern, i>
        >;
        default: excluded;
        custom: excluded extends infer narrowedOrFn extends Fn
          ? Call<narrowedOrFn, i>
          : excluded;
      }[matcherType]
    : p extends readonly any[]
    ? Extract<i, readonly any[]> extends infer arrayInput
      ? InvertArrayPatternForExclude<
          p,
          arrayInput,
          empty,
          IsReadonlyArray<arrayInput>
        >
      : never
    : IsPlainObject<p> extends true
    ? Equal<{}, p> extends true
      ? {}
      : i extends object
      ? [keyof p & keyof i] extends [never]
        ? empty
        : OptionalKeys<p> extends infer optKeys
        ? [optKeys] extends [never]
          ? {
              readonly [k in keyof p]: k extends keyof i
                ? InvertPatternForExcludeInternal<p[k], i[k], empty>
                : InvertPatternInternal<p[k], unknown>;
            }
          : Compute<
              {
                readonly [k in Exclude<keyof p, optKeys>]: k extends keyof i
                  ? InvertPatternForExcludeInternal<p[k], i[k], empty>
                  : InvertPatternInternal<p[k], unknown>;
              } & {
                readonly [k in Extract<optKeys, keyof p>]?: k extends keyof i
                  ? InvertPatternForExcludeInternal<p[k], i[k], empty>
                  : InvertPatternInternal<p[k], unknown>;
              }
            >
        : empty
      : empty
    : empty;


================================================
FILE: src/types/IsMatching.ts
================================================
import {
  Primitives,
  IsPlainObject,
  IsUnion,
  ValueOf,
  Length,
  IsLiteral,
  All,
  Equal,
} from './helpers';

type IsMatchingTuple<a extends readonly any[], b extends readonly any[]> = [
  a,
  b
] extends [readonly [], readonly []]
  ? true
  : [a, b] extends [
      readonly [infer a1, ...infer aRest],
      readonly [infer b1, ...infer bRest]
    ]
  ? IsMatching<a1, b1> extends true
    ? IsMatchingTuple<aRest, bRest>
    : false
  : false;

type IsMatchingArray<
  a extends readonly any[],
  b extends readonly any[]
> = b extends readonly []
  ? true // if b is an empty array and a is an array, the pattern matches.
  : b extends readonly [infer b1, ...infer bRest]
  ? a extends readonly [infer a1, ...infer aRest]
    ? IsMatching<a1, b1> extends true
      ? IsMatchingArray<aRest, bRest>
      : false
    : // if a is shorter than b, doesn't match
    // example: a is [], b is [any, ...any[]]
    a extends readonly []
    ? false
    : IsMatching<ValueOf<a>, b1> extends true
    ? IsMatchingArray<a, bRest>
    : false
  : b extends readonly [...infer bInit, infer b1]
  ? a extends readonly [...infer aInit, infer a1]
    ? IsMatching<a1, b1> extends true
      ? IsMatchingArray<aInit, bInit>
      : false
    : // if a is shorter than b, doesn't match
    // example: a is [], b is [any, ...any[]]
    a extends readonly []
    ? false
    : IsMatching<ValueOf<a>, b1> extends true
    ? IsMatchingArray<a, bInit>
    : false
  : IsMatching<ValueOf<a>, ValueOf<b>>;

export type IsMatching<a, b> = true extends IsUnion<a> | IsUnion<b>
  ? true extends (
      b extends any ? (a extends any ? IsMatching<a, b> : never) : never
    )
    ? true
    : false
  : // Special case for unknown, because this is the type
  // of the inverted `_` wildcard pattern, which should
  // match everything.
  unknown extends b
  ? true
  : // Special case for `{}`, because this is the type
  // of the inverted `P.nonNullable` wildcard pattern,
  // which should match all objects.
  {} extends b
  ? true
  : b extends Primitives
  ? // if the pattern is a primitive, we want to check if there is
    // an overlap between a and b!
    a extends b
    ? true
    : b extends a
    ? true
    : false
  : Equal<a, b> extends true
  ? true
  : b extends readonly any[]
  ? a extends readonly any[]
    ? // both tuples
      All<[IsLiteral<Length<a>>, IsLiteral<Length<b>>]> extends true
      ? // lengths are different
        Equal<Length<a>, Length<b>> extends false
        ? false
        : IsMatchingTuple<a, b>
      : IsMatchingArray<a, b>
    : false
  : IsPlainObject<b> extends true
  ? true extends ( // `true extends union` means "if some cases of the a union are matching"
      a extends any // loop over the `a` union
        ? [keyof b & keyof a] extends [never] // if no common keys
          ? false
          : /**
           * Intentionally not using ValueOf, to avoid reaching the
           * 'type instanciation is too deep error'.
           */
          { [k in keyof b & keyof a]: IsMatching<a[k], b[k]> }[keyof b &
              keyof a] extends true
          ? true // all values are matching
          : false
        : never
    )
    ? true
    : false
  : b extends a
  ? true
  : false;


================================================
FILE: src/types/Match.ts
================================================
import type * as symbols from '../internals/symbols';
import type { Pattern, MatchedValue } from './Pattern';
import type { InvertPatternForExclude, InvertPattern } from './InvertPattern';
import type { DeepExclude } from './DeepExclude';
import type { Union, GuardValue, IsNever } from './helpers';
import type { FindSelected } from './FindSelected';

export type PickReturnValue<a, b> = a extends symbols.unset ? b : a;

interface NonExhaustiveError<i> {
  __nonExhaustive: never;
}

interface TSPatternError<i> {
  __nonExhaustive: never;
}

/**
 * #### Match
 * An interface to create a pattern matching clause.
 */
export type Match<
  i,
  o,
  handledCases extends any[] = [],
  inferredOutput = never
> = {
  /**
   * `.with(pattern, handler)` Registers a pattern and an handler function that
   * will be called if the pattern matches the input value.
   *
   * [Read the documentation for `.with()` on GitHub](https://github.com/gvergnaud/ts-pattern#with)
   **/
  with<
    const p extends Pattern<i>,
    c,
    value extends MatchedValue<i, InvertPattern<p, i>>
  >(
    pattern: IsNever<p> extends true
      ? /**
         * HACK: Using `IsNever<p>` here is a hack to
         * make sure the type checker forwards
         * the input type parameter to pattern
         * creator functions like `P.when`, `P.not`
         * `P.union` when they are passed to `.with`
         * directly.
         */
        Pattern<i>
      : p,
    handler: (
      selections: FindSelected<value, p>,
      value: value
    ) => PickReturnValue<o, c>
  ): InvertPatternForExclude<p, value> extends infer excluded
    ? Match<
        Exclude<i, excluded>,
        o,
        [...handledCases, excluded],
        Union<inferredOutput, c>
      >
    : never;

  with<
    const p1 extends Pattern<i>,
    const p2 extends Pattern<i>,
    c,
    p extends p1 | p2,
    value extends p extends any ? MatchedValue<i, InvertPattern<p, i>> : never
  >(
    p1: p1,
    p2: p2,
    handler: (value: value) => PickReturnValue<o, c>
  ): [
    InvertPatternForExclude<p1, value>,
    InvertPatternForExclude<p2, value>
  ] extends [infer excluded1, infer excluded2]
    ? Match<
        Exclude<i, excluded1 | excluded2>,
        o,
        [...handledCases, excluded1, excluded2],
        Union<inferredOutput, c>
      >
    : never;

  with<
    const p1 extends Pattern<i>,
    const p2 extends Pattern<i>,
    const p3 extends Pattern<i>,
    const ps extends readonly Pattern<i>[],
    c,
    p extends p1 | p2 | p3 | ps[number],
    value extends MatchedValue<i, InvertPattern<p, i>>
  >(
    ...args: [
      p1: p1,
      p2: p2,
      p3: p3,
      ...patterns: ps,
      handler: (value: value) => PickReturnValue<o, c>
    ]
  ): [
    InvertPatternForExclude<p1, value>,
    InvertPatternForExclude<p2, value>,
    InvertPatternForExclude<p3, value>,
    MakeTuples<ps, value>
  ] extends [
    infer excluded1,
    infer excluded2,
    infer excluded3,
    infer excludedRest
  ]
    ? Match<
        Exclude<
          i,
          | excluded1
          | excluded2
          | excluded3
          | Extract<excludedRest, any[]>[number]
        >,
        o,
        [
          ...handledCases,
          excluded1,
          excluded2,
          excluded3,
          ...Extract<excludedRest, any[]>
        ],
        Union<inferredOutput, c>
      >
    : never;

  with<
    const pat extends Pattern<i>,
    pred extends (value: MatchedValue<i, InvertPattern<pat, i>>) => unknown,
    c,
    value extends GuardValue<pred>
  >(
    pattern: pat,
    predicate: pred,
    handler: (
      selections: FindSelected<value, pat>,
      value: value
    ) => PickReturnValue<o, c>
  ): pred extends (value: any) => value is infer narrowed
    ? Match<
        Exclude<i, narrowed>,
        o,
        [...handledCases, narrowed],
        Union<inferredOutput, c>
      >
    : Match<i, o, handledCases, Union<inferredOutput, c>>;

  /**
   * `.when(predicate, handler)` Registers a predicate function and an handler function.
   * If the predicate returns true, the handler function will be called.
   *
   * [Read the documentation for `.when()` on GitHub](https://github.com/gvergnaud/ts-pattern#when)
   **/
  when<pred extends (value: i) => unknown, c, value extends GuardValue<pred>>(
    predicate: pred,
    handler: (value: value) => PickReturnValue<o, c>
  ): pred extends (value: any) => value is infer narrowed
    ? Match<
        Exclude<i, narrowed>,
        o,
        [...handledCases, narrowed],
        Union<inferredOutput, c>
      >
    : Match<i, o, handledCases, Union<inferredOutput, c>>;

  /**
   * `.otherwise()` takes a **default handler function** that will be
   * called if no previous pattern matched your input.
   *
   * Equivalent to `.with(P._, () => x).exhaustive()`
   *
   * [Read the documentation for `.otherwise()` on GitHub](https://github.com/gvergnaud/ts-pattern#otherwise)
   *
   **/
  otherwise<c>(
    handler: (value: i) => PickReturnValue<o, c>
  ): PickReturnValue<o, Union<inferredOutput, c>>;

  /**
   * `.exhaustive()` checks that all cases are handled, and returns the result value.
   *
   * If you get a `NonExhaustiveError`, it means that you aren't handling
   * all cases. You should probably add another `.with(...)` clause
   * to match the missing case and prevent runtime errors.
   *
   * [Read the documentation for `.exhaustive()` on GitHub](https://github.com/gvergnaud/ts-pattern#exhaustive)
   *
   */
  exhaustive: DeepExcludeAll<i, handledCases> extends infer remainingCases
    ? [remainingCases] extends [never]
      ? Exhaustive<o, inferredOutput>
      : NonExhaustiveError<remainingCases>
    : never;

  /**
   * `.run()` return the resulting value.
   *
   * ⚠️ calling this function is unsafe, and may throw if no pattern matches your input.
   */
  run(): PickReturnValue<o, inferredOutput>;

  /**
   * `.returnType<T>()` Lets you specify the return type for all of your branches.
   *
   * [Read the documentation for `.returnType()` on GitHub](https://github.com/gvergnaud/ts-pattern#returnType)
   */
  returnType: [inferredOutput] extends [never]
    ? <output>() => Match<i, output, handledCases>
    : TSPatternError<'calling `.returnType<T>()` is only allowed directly after `match(...)`.'>;

  /**
   * `.narrow()` narrows the input type to exclude all cases that have previously been handled.
   *
   * `.narrow()` is only useful if you want to excluded cases from union types or nullable
   * properties that are deeply nested. Handled cases from top level union types are excluded
   * by default.
   *
   * [Read the documentation for `.narrow() on GitHub](https://github.com/gvergnaud/ts-pattern#narrow)
   */
  narrow(): Match<DeepExcludeAll<i, handledCases>, o, [], inferredOutput>;
};

/**
 * Potential for optimization here:
 *
 * Since DeepExclude distributes the union of the input type, it can
 * generate very large union types on patterns touching several unions at once.
 * If we were sorting patterns from those which distribute the smallest
 * amount of union types to those which distribute the largest, we would eliminate
 * cheap cases more quickly and have less cases in the input type for patterns
 * that will be expensive to exclude.
 *
 * This pre supposes that we have a cheap way of telling if the number
 * of union types a pattern touches and a cheap way of sorting the tuple
 * of patterns.
 * - For the first part, we could reuse `FindMatchingUnions` and pick the `length`
 *   of the returned tuple.
 * - For the second part though I'm not aware a cheap way of sorting a tuple.
 */
type DeepExcludeAll<a, tupleList extends any[]> = [a] extends [never]
  ? never
  : tupleList extends [infer excluded, ...infer tail]
  ? DeepExcludeAll<DeepExclude<a, excluded>, tail>
  : a;

type MakeTuples<ps extends readonly any[], value> = {
  -readonly [index in keyof ps]: InvertPatternForExclude<ps[index], value>;
};

/**
 * The type of an overloaded function for `.exhaustive`,
 * permitting calling it with or without a catch-all handler function.
 *
 * By default, TS-Pattern will throw an error if a runtime value isn't handled.
 */
type Exhaustive<output, inferredOutput> = {
  /**
   * `.exhaustive()` checks that all cases are handled, and returns the result value.
   *
   * If you get a `NonExhaustiveError`, it means that you aren't handling
   * all cases. You should probably add another `.with(...)` clause
   * to match the missing case and prevent runtime errors.
   *
   * [Read the documentation for `.exhaustive()` on GitHub](https://github.com/gvergnaud/ts-pattern#exhaustive)
   *
   */
  (): PickReturnValue<output, inferredOutput>;
  /**
   * `.exhaustive(fallback)` checks that all cases are handled and returns the result value.
   *
   * The fallback function will be called if your input value doesn't match any pattern.
   * This can only happen if the value you passed to `match` has an incorrect type.
   *
   * If you get a `NonExhaustiveError`, it means that you aren't handling
   * all cases. You should probably add another `.with(...)` clause
   * to match the missing case.
   *
   * [Read the documentation for `.exhaustive()` on GitHub](https://github.com/gvergnaud/ts-pattern#exhaustive)
   */
  <otherOutput>(
    handler: (unexpectedValue: unknown) => PickReturnValue<output, otherOutput>
  ): PickReturnValue<output, Union<inferredOutput, otherOutput>>;
};


================================================
FILE: src/types/Pattern.ts
================================================
import type * as symbols from '../internals/symbols';
import { MergeUnion, Primitives, WithDefault } from './helpers';
import { None, Some, SelectionType } from './FindSelected';
import { matcher } from '../patterns';
import { ExtractPreciseValue } from './ExtractPreciseValue';

export type MatcherType =
  | 'not'
  | 'optional'
  | 'or'
  | 'and'
  | 'array'
  | 'record'
  | 'map'
  | 'set'
  | 'select'
  | 'default'
  | 'custom';

// We use a separate MatcherProtocol type to preserves
// the type level information (selections and excluded) used
// only for inference.
export type MatcherProtocol<
  input,
  narrowed,
  // Type of what this pattern selected from the input
  matcherType extends MatcherType,
  selections extends SelectionType,
  // Type to exclude from the input union because
  // it has been fully matched by this pattern
  excluded
> = {
  match: <I>(value: I | input) => MatchResult;
  getSelectionKeys?: () => string[];
  matcherType?: matcherType;
};

export type MatchResult = {
  matched: boolean;
  selections?: Record<string, any>;
};

/**
 * A `Matcher` is an object implementing the match
 * protocol. It must define a `symbols.matcher` property
 * which returns an object with a `match()` method, taking
 * the input value and returning whether the pattern matches
 * or not, along with optional selections.
 */
export interface Matcher<
  input,
  narrowed,
  // Type of what this pattern selected from the input
  matcherType extends MatcherType = 'default',
  selections extends SelectionType = None,
  // Type to exclude from the input union because
  // it has been fully matched by this pattern
  excluded = narrowed
> {
  [matcher](): MatcherProtocol<
    input,
    narrowed,
    matcherType,
    selections,
    excluded
  >;
  // only used for array matchers
  [symbols.isVariadic]?: boolean;
}

type PatternMatcher<input> = Matcher<input, unknown, any, any>;

// We fall back to `a` if we weren't able to extract anything more precise
export type MatchedValue<a, invpattern> = WithDefault<
  ExtractPreciseValue<a, invpattern>,
  a
>;

export type AnyMatcher = Matcher<any, any, any, any, any>;

type UnknownMatcher = PatternMatcher<unknown>;

export type CustomP<input, pattern, narrowedOrFn> = Matcher<
  input,
  pattern,
  //  👆
  // for the input type to be instantiated correctly
  // on subpatterns, it has to be passed through.
  'custom',
  None,
  narrowedOrFn
>;

export type ArrayP<input, p> = Matcher<input, p, 'array'>;

export type RecordP<input, pkey, pvalue> = Matcher<
  input,
  [pkey, pvalue],
  'record'
>;

export type OptionalP<input, p> = Matcher<input, p, 'optional'>;

export type MapP<input, pkey, pvalue> = Matcher<input, [pkey, pvalue], 'map'>;

export type SetP<input, p> = Matcher<input, p, 'set'>;

export type AndP<input, ps> = Matcher<input, ps, 'and'>;

export type OrP<input, ps> = Matcher<input, ps, 'or'>;

export type NotP<input, p> = Matcher<input, p, 'not'>;

export type GuardP<input, narrowed> = Matcher<input, narrowed>;

export type GuardExclude
Download .txt
gitextract_ejzj_xdd/

├── .github/
│   ├── FUNDING.yml
│   └── ISSUE_TEMPLATE/
│       ├── bug_report.md
│       └── feature_request.md
├── .gitignore
├── .prettierrc
├── LICENSE
├── README.md
├── benchmarks/
│   ├── always-last-digit.ts
│   ├── nested-objects.ts
│   ├── package.json
│   └── random-digit.ts
├── docs/
│   ├── roadmap.md
│   ├── v3-to-v4-migration-guide.md
│   └── v4-to-v5-migration-guide.md
├── examples/
│   ├── gif-fetcher/
│   │   ├── package.json
│   │   ├── public/
│   │   │   └── index.html
│   │   ├── src/
│   │   │   ├── App.tsx
│   │   │   ├── constants.ts
│   │   │   ├── index.tsx
│   │   │   ├── searchGif.ts
│   │   │   └── styles.css
│   │   └── tsconfig.json
│   └── one-file-demo/
│       ├── one-file-demo.ts
│       ├── package.json
│       └── tsconfig.json
├── jest.config.cjs
├── jsr.json
├── package.json
├── scripts/
│   └── generate-cts.sh
├── src/
│   ├── errors.ts
│   ├── index.ts
│   ├── internals/
│   │   ├── helpers.ts
│   │   └── symbols.ts
│   ├── is-matching.ts
│   ├── match.ts
│   ├── patterns.ts
│   └── types/
│       ├── BuildMany.ts
│       ├── DeepExclude.ts
│       ├── DistributeUnions.ts
│       ├── ExtractPreciseValue.ts
│       ├── FindSelected.ts
│       ├── InvertPattern.ts
│       ├── IsMatching.ts
│       ├── Match.ts
│       ├── Pattern.ts
│       ├── helpers.ts
│       └── index.ts
├── tests/
│   ├── bigints.test.ts
│   ├── branded-nominal-types.test.ts
│   ├── build-many.test.ts
│   ├── chainable.test.ts
│   ├── deep-exclude.test.ts
│   ├── distribute-unions.test.ts
│   ├── exhaustive-fallback.test.ts
│   ├── exhaustive-match.test.ts
│   ├── extract-precise-value.test.ts
│   ├── find-selected.test.ts
│   ├── generics.test.ts
│   ├── helpers.test.ts
│   ├── infer.test.ts
│   ├── instance-of.test.ts
│   ├── intersection-and-union.test.ts
│   ├── invert-pattern.test.ts
│   ├── is-matching.test.ts
│   ├── large-exhaustive.test.ts
│   ├── lists.test.ts
│   ├── maps.test.ts
│   ├── matcher-protocol.test.ts
│   ├── multiple-patterns.test.ts
│   ├── narrow.test.ts
│   ├── nesting.test.ts
│   ├── not.test.ts
│   ├── numbers.test.ts
│   ├── objects.test.ts
│   ├── optional-props.test.ts
│   ├── optional.test.ts
│   ├── otherwise.test.ts
│   ├── output-type.test.ts
│   ├── pattern.test.ts
│   ├── primitive-values.test.ts
│   ├── readonly.test.ts
│   ├── real-world.test.ts
│   ├── record.test.ts
│   ├── return-type.test.ts
│   ├── select.test.ts
│   ├── sets.test.ts
│   ├── strings.test.ts
│   ├── tsconfig.json
│   ├── tuples.test.ts
│   ├── type-error.test.ts
│   ├── type-is-matching.test.ts
│   ├── types-catalog/
│   │   ├── definition.ts
│   │   └── utils.ts
│   ├── types.test.ts
│   ├── unions.test.ts
│   ├── variadic-tuples.test.ts
│   ├── when.test.ts
│   └── wildcards.test.ts
└── tsconfig.json
Download .txt
SYMBOL INDEX (1440 symbols across 69 files)

FILE: benchmarks/always-last-digit.ts
  type Digit (line 4) | type Digit = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;

FILE: benchmarks/random-digit.ts
  type Digit (line 4) | type Digit = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;

FILE: examples/gif-fetcher/src/App.tsx
  type State (line 11) | type State = {
  type Event (line 24) | type Event =
  function App (line 75) | function App() {

FILE: examples/gif-fetcher/src/constants.ts
  constant API_KEY (line 1) | const API_KEY = 'xxxxxxxxxxxxxxxx';

FILE: examples/gif-fetcher/src/searchGif.ts
  function searchGif (line 6) | function searchGif(query: string) {

FILE: examples/one-file-demo/one-file-demo.ts
  type Response (line 20) | type Response =
  type UserType (line 56) | type UserType = 'editor' | 'viewer';
  type OrgPlan (line 58) | type OrgPlan = 'basic' | 'pro' | 'premium';
  type User (line 112) | type User = P.infer<typeof User>;
  type Post (line 133) | type Post = P.infer<typeof Post>;

FILE: src/errors.ts
  class NonExhaustiveError (line 5) | class NonExhaustiveError extends Error {
    method constructor (line 6) | constructor(public input: unknown) {

FILE: src/internals/symbols.ts
  type matcher (line 17) | type matcher = typeof matcher;
  type unset (line 20) | type unset = typeof unset;
  type isVariadic (line 23) | type isVariadic = typeof isVariadic;
  type anonymousSelectKey (line 27) | type anonymousSelectKey = typeof anonymousSelectKey;
  type override (line 30) | type override = typeof override;

FILE: src/is-matching.ts
  type PatternConstraint (line 11) | type PatternConstraint<T> = T extends readonly any[]
  function isMatching (line 53) | function isMatching<const p extends Pattern<any>>(

FILE: src/match.ts
  type MatchState (line 7) | type MatchState<output> =
  function match (line 32) | function match<const input, output = symbols.unset>(
  class MatchExpression (line 47) | class MatchExpression<input, output> {
    method constructor (line 48) | constructor(private input: input, private state: MatchState<output>) {}
    method with (line 50) | with(...args: any[]): MatchExpression<input, output> {
    method when (line 94) | when(
    method otherwise (line 110) | otherwise(handler: (value: input) => output): output {
    method exhaustive (line 115) | exhaustive(unexpectedValueHandler = defaultCatcher): output {
    method run (line 120) | run(): output {
    method returnType (line 124) | returnType() {
    method narrow (line 128) | narrow() {
  function defaultCatcher (line 133) | function defaultCatcher(input: unknown): never {

FILE: src/patterns.ts
  type unstable_Matchable (line 81) | type unstable_Matchable<
  type unstable_Matcher (line 100) | type unstable_Matcher<
  type infer (line 116) | type infer<pattern> = InvertPattern<NoInfer<pattern>, unknown>;
  type narrow (line 131) | type narrow<input, pattern> = ExtractPreciseValue<
  function chainable (line 136) | function chainable<pattern extends Matcher<any, any, any, any, any>>(
  method [Symbol.iterator] (line 150) | [Symbol.iterator](): Iterator<pattern, void, undefined> {
  function arrayChainable (line 165) | function arrayChainable<pattern extends Matcher<any, any, any, any, any>>(
  function optional (line 187) | function optional<
  type UnwrapArray (line 217) | type UnwrapArray<xs> = xs extends readonly (infer x)[] ? x : never;
  type UnwrapSet (line 219) | type UnwrapSet<xs> = xs extends Set<infer x> ? x : never;
  type UnwrapMapKey (line 221) | type UnwrapMapKey<xs> = xs extends Map<infer k, any> ? k : never;
  type UnwrapMapValue (line 223) | type UnwrapMapValue<xs> = xs extends Map<any, infer v> ? v : never;
  type UnwrapRecordKey (line 225) | type UnwrapRecordKey<xs> = xs extends Record<infer k, any> ? k : never;
  type UnwrapRecordValue (line 227) | type UnwrapRecordValue<xs> = xs extends Record<any, infer v> ? v : never;
  type WithDefault (line 229) | type WithDefault<a, b> = [a] extends [never] ? b : a;
  function array (line 246) | function array(
  function set (line 299) | function set<
  function map (line 362) | function map<
  function record (line 445) | function record(
  function intersection (line 536) | function intersection<
  function union (line 572) | function union<
  function not (line 611) | function not<
  function when (line 646) | function when<input, predicate extends (value: input) => unknown>(
  function select (line 696) | function select(
  function isUnknown (line 734) | function isUnknown(x: unknown): x is unknown {
  function isNumber (line 738) | function isNumber<T>(x: T | number): x is number {
  function isString (line 742) | function isString<T>(x: T | string): x is string {
  function isBoolean (line 746) | function isBoolean<T>(x: T | boolean): x is boolean {
  function isBigInt (line 750) | function isBigInt<T>(x: T | bigint): x is bigint {
  function isSymbol (line 754) | function isSymbol<T>(x: T | symbol): x is symbol {
  function isNullish (line 758) | function isNullish<T>(x: T | null | undefined): x is null | undefined {
  function isNonNullable (line 762) | function isNonNullable(x: unknown): x is {} {
  type AnyConstructor (line 766) | type AnyConstructor = abstract new (...args: any[]) => any;
  function isInstanceOf (line 768) | function isInstanceOf<T extends AnyConstructor>(classConstructor: T) {
  function instanceOf (line 1251) | function instanceOf<T extends AnyConstructor>(
  function shape (line 1274) | function shape(pattern: UnknownValuePattern) {

FILE: src/types/BuildMany.ts
  type BuildMany (line 4) | type BuildMany<data, xs extends readonly any[]> = xs extends any
  type BuildOne (line 11) | type BuildOne<data, xs extends readonly any[]> = xs extends [
  type SetDeep (line 19) | type SetDeep<data, value, path> = path extends readonly [

FILE: src/types/DeepExclude.ts
  type DeepExclude (line 3) | type DeepExclude<a, b> = Exclude<DistributeMatchingUnions<a, b>, b>;

FILE: src/types/DistributeUnions.ts
  type DistributeMatchingUnions (line 41) | type DistributeMatchingUnions<a, p> = IsAny<a> extends true
  type FindUnionsMany (line 46) | type FindUnionsMany<
  type FindUnions (line 80) | type FindUnions<
  type ArrayToVariadicUnion (line 174) | type ArrayToVariadicUnion<input, excluded> = MaybeAddReadonly<
  type Distribute (line 183) | type Distribute<unions extends readonly any[]> =

FILE: src/types/ExtractPreciseValue.ts
  type ExtractPreciseValue (line 13) | type ExtractPreciseValue<a, b> = b extends Override<infer b1>
  type ExtractPreciseArrayValue (line 81) | type ExtractPreciseArrayValue<

FILE: src/types/FindSelected.ts
  type SelectionsRecord (line 11) | type SelectionsRecord = Record<string, [unknown, unknown[]]>;
  type None (line 13) | type None = {
  type Some (line 16) | type Some<key extends string> = {
  type SelectionType (line 21) | type SelectionType = None | Some<string>;
  type MapOptional (line 24) | type MapOptional<selections> = {
  type MapList (line 31) | type MapList<selections> = {
  type ReduceFindSelectionUnion (line 38) | type ReduceFindSelectionUnion<
  type FindSelectionUnionInArray (line 47) | type FindSelectionUnionInArray<
  type FindSelectionUnion (line 96) | type FindSelectionUnion<
  type SeveralAnonymousSelectError (line 159) | type SeveralAnonymousSelectError<
  type MixedNamedAndAnonymousSelectError (line 165) | type MixedNamedAndAnonymousSelectError<
  type SelectionToArgs (line 174) | type SelectionToArgs<selections extends SelectionsRecord> =
  type Selections (line 185) | type Selections<i, p> = FindSelectionUnion<i, p> extends infer u
  type FindSelected (line 191) | type FindSelected<i, p> =

FILE: src/types/InvertPattern.ts
  type OptionalKeys (line 29) | type OptionalKeys<p> = ValueOf<{
  type ReduceUnion (line 39) | type ReduceUnion<
  type ReduceIntersection (line 47) | type ReduceIntersection<
  type InvertArrayPattern (line 55) | type InvertArrayPattern<
  type InvertPattern (line 106) | type InvertPattern<p, input> = Equal<Pattern<input>, p> extends true
  type InvertPatternInternal (line 110) | type InvertPatternInternal<p, input> = 0 extends 1 & p
  type ReduceIntersectionForExclude (line 180) | type ReduceIntersectionForExclude<
  type ReduceUnionForExclude (line 192) | type ReduceUnionForExclude<
  type ExcludeIfExists (line 204) | type ExcludeIfExists<a, b> =
  type InvertArrayPatternForExclude (line 231) | type InvertArrayPatternForExclude<
  type InvertPatternForExclude (line 303) | type InvertPatternForExclude<p, i> = Equal<Pattern<i>, p> extends true
  type InvertPatternForExcludeInternal (line 307) | type InvertPatternForExcludeInternal<p, i, empty = never> =

FILE: src/types/IsMatching.ts
  type IsMatchingTuple (line 12) | type IsMatchingTuple<a extends readonly any[], b extends readonly any[]>...
  type IsMatchingArray (line 26) | type IsMatchingArray<
  type IsMatching (line 57) | type IsMatching<a, b> = true extends IsUnion<a> | IsUnion<b>

FILE: src/types/Match.ts
  type PickReturnValue (line 8) | type PickReturnValue<a, b> = a extends symbols.unset ? b : a;
  type NonExhaustiveError (line 10) | interface NonExhaustiveError<i> {
  type TSPatternError (line 14) | interface TSPatternError<i> {
  type Match (line 22) | type Match<
  type DeepExcludeAll (line 245) | type DeepExcludeAll<a, tupleList extends any[]> = [a] extends [never]
  type MakeTuples (line 251) | type MakeTuples<ps extends readonly any[], value> = {
  type Exhaustive (line 261) | type Exhaustive<output, inferredOutput> = {

FILE: src/types/Pattern.ts
  type MatcherType (line 7) | type MatcherType =
  type MatcherProtocol (line 23) | type MatcherProtocol<
  type MatchResult (line 38) | type MatchResult = {
  type Matcher (line 50) | interface Matcher<
  type PatternMatcher (line 71) | type PatternMatcher<input> = Matcher<input, unknown, any, any>;
  type MatchedValue (line 74) | type MatchedValue<a, invpattern> = WithDefault<
  type AnyMatcher (line 79) | type AnyMatcher = Matcher<any, any, any, any, any>;
  type UnknownMatcher (line 81) | type UnknownMatcher = PatternMatcher<unknown>;
  type CustomP (line 83) | type CustomP<input, pattern, narrowedOrFn> = Matcher<
  type ArrayP (line 94) | type ArrayP<input, p> = Matcher<input, p, 'array'>;
  type RecordP (line 96) | type RecordP<input, pkey, pvalue> = Matcher<
  type OptionalP (line 102) | type OptionalP<input, p> = Matcher<input, p, 'optional'>;
  type MapP (line 104) | type MapP<input, pkey, pvalue> = Matcher<input, [pkey, pvalue], 'map'>;
  type SetP (line 106) | type SetP<input, p> = Matcher<input, p, 'set'>;
  type AndP (line 108) | type AndP<input, ps> = Matcher<input, ps, 'and'>;
  type OrP (line 110) | type OrP<input, ps> = Matcher<input, ps, 'or'>;
  type NotP (line 112) | type NotP<input, p> = Matcher<input, p, 'not'>;
  type GuardP (line 114) | type GuardP<input, narrowed> = Matcher<input, narrowed>;
  type GuardExcludeP (line 116) | type GuardExcludeP<input, narrowed, excluded> = Matcher<
  type SelectP (line 124) | type SelectP<
  type AnonymousSelectP (line 130) | type AnonymousSelectP = SelectP<symbols.anonymousSelectKey>;
  type Override (line 132) | interface Override<a> {
  type UnknownProperties (line 136) | type UnknownProperties = { readonly [k: PropertyKey]: unknown };
  type UnknownValuePattern (line 138) | type UnknownValuePattern =
  type Pattern (line 157) | type Pattern<a = unknown> = unknown extends a
  type KnownPattern (line 161) | type KnownPattern<a> = KnownPatternInternal<a>;
  type KnownPatternInternal (line 163) | type KnownPatternInternal<
  type ObjectPattern (line 174) | type ObjectPattern<a> =
  type ArrayPattern (line 180) | type ArrayPattern<a> = a extends readonly (infer i)[]
  type UnknownPattern (line 190) | type UnknownPattern = Chainable<GuardP<unknown, unknown>, never>;
  type StringPattern (line 191) | type StringPattern = StringChainable<GuardP<unknown, string>, never>;
  type NumberPattern (line 192) | type NumberPattern = NumberChainable<GuardP<unknown, number>, never>;
  type BooleanPattern (line 193) | type BooleanPattern = Chainable<GuardP<unknown, boolean>, never>;
  type BigIntPattern (line 194) | type BigIntPattern = BigIntChainable<GuardP<unknown, bigint>, never>;
  type SymbolPattern (line 195) | type SymbolPattern = Chainable<GuardP<unknown, symbol>, never>;
  type NullishPattern (line 196) | type NullishPattern = Chainable<
  type NonNullablePattern (line 201) | type NonNullablePattern = Chainable<GuardP<unknown, {}>, never>;
  type MergeGuards (line 203) | type MergeGuards<input, guard1, guard2> = [guard1, guard2] extends [
  type Chainable (line 210) | type Chainable<p, omitted extends string = never> = p &
  type StringChainable (line 276) | type StringChainable<
  type NumberChainable (line 391) | type NumberChainable<p, omitted extends string = never> = Chainable<
  type BigIntChainable (line 530) | type BigIntChainable<p, omitted extends string = never> = Chainable<
  type Variadic (line 643) | type Variadic<pattern> = pattern & Iterable<pattern>;
  type ArrayChainable (line 645) | type ArrayChainable<

FILE: src/types/helpers.ts
  type ValueOf (line 1) | type ValueOf<a> = a extends readonly any[] ? a[number] : a[keyof a];
  type Values (line 3) | type Values<a extends object> = UnionToTuple<ValueOf<a>>;
  type LeastUpperBound (line 14) | type LeastUpperBound<a, b> = b extends a ? b : a extends b ? a : never;
  type Contains (line 16) | type Contains<a, b> = a extends any
  type UnionToIntersection (line 25) | type UnionToIntersection<union> = (
  type IsUnion (line 31) | type IsUnion<a> = [a] extends [UnionToIntersection<a>] ? false : true;
  type UnionToTuple (line 33) | type UnionToTuple<
  type Flatten (line 42) | type Flatten<
  type Equal (line 49) | type Equal<a, b> = (<T>() => T extends a ? 1 : 2) extends <
  type Expect (line 55) | type Expect<a extends true> = a;
  type IsAny (line 57) | type IsAny<a> = 0 extends 1 & a ? true : false;
  type IsNever (line 59) | type IsNever<T> = [T] extends [never] ? true : false;
  type Length (line 61) | type Length<it extends readonly any[]> = it['length'];
  type Iterator (line 63) | type Iterator<
  type Next (line 68) | type Next<it extends any[]> = [any, ...it];
  type Prev (line 69) | type Prev<it extends any[]> = it extends readonly [any, ...infer tail]
  type Take (line 73) | type Take<
  type Drop (line 83) | type Drop<
  type UpdateAt (line 92) | type UpdateAt<
  type BuiltInObjects (line 105) | type BuiltInObjects =
  type IsPlainObject (line 113) | type IsPlainObject<o, excludeUnion = BuiltInObjects> = o extends object
  type Compute (line 122) | type Compute<a extends any> = a extends BuiltInObjects
  type IntersectObjects (line 126) | type IntersectObjects<a> = (
  type WithDefault (line 138) | type WithDefault<a, def> = [a] extends [never] ? def : a;
  type IsLiteral (line 140) | type IsLiteral<a> = [a] extends [null | undefined]
  type Primitives (line 164) | type Primitives =
  type NonLiteralPrimitive (line 173) | type NonLiteralPrimitive = Exclude<Primitives, undefined | null>;
  type TupleKeys (line 175) | type TupleKeys = '0' | '1' | '2' | '3' | '4';
  type Union (line 177) | type Union<a, b> = [b] extends [a] ? a : [a] extends [b] ? b : a | b;
  type GuardValue (line 182) | type GuardValue<fn> = fn extends (value: any) => value is infer b
  type GuardFunction (line 188) | type GuardFunction<input, narrowed> =
  type Some (line 192) | type Some<bools extends boolean[]> = true extends bools[number]
  type All (line 196) | type All<bools extends boolean[]> = bools[number] extends true
  type Extends (line 200) | type Extends<a, b> = [a] extends [b] ? true : false;
  type Not (line 202) | type Not<a extends boolean> = a extends true ? false : true;
  type AllKeys (line 204) | type AllKeys<a> = a extends any ? keyof a : never;
  type MergeUnion (line 207) | type MergeUnion<a> =
  type IsFixedSizeTuple (line 217) | type IsFixedSizeTuple<a extends readonly any[]> = IsLiteral<Length<a>>;
  type IsTuple (line 220) | type IsTuple<a> = a extends
  type IsStrictArray (line 227) | type IsStrictArray<a extends readonly any[]> = Not<IsTuple<a>>;
  type IsReadonlyArray (line 229) | type IsReadonlyArray<a> = a extends readonly any[]
  type MaybeAddReadonly (line 235) | type MaybeAddReadonly<
  type MapKey (line 240) | type MapKey<T> = T extends Map<infer K, any> ? K : never;
  type MapValue (line 242) | type MapValue<T> = T extends Map<any, infer V> ? V : never;
  type SetValue (line 244) | type SetValue<T> = T extends Set<infer V> ? V : never;
  type RecordKey (line 246) | type RecordKey<T> = T extends Record<infer K, any> ? K : never;
  type RecordValue (line 248) | type RecordValue<T> = T extends Record<any, infer V> ? V : never;
  type ReadonlyArrayValue (line 250) | type ReadonlyArrayValue<T> = T extends ReadonlyArray<infer V>
  type ExtractPlainObject (line 254) | type ExtractPlainObject<T> = T extends any
  type GetKey (line 260) | type GetKey<O, K> = O extends any
  type Fn (line 266) | interface Fn {
  type Call (line 271) | type Call<fn extends Fn, input> = (fn & {
  type IsOptionalKeysOf (line 275) | type IsOptionalKeysOf<obj, key extends keyof obj> = {} extends Pick<

FILE: tests/bigints.test.ts
  type t (line 9) | type t = Expect<Equal<typeof value, bigint>>;
  type t (line 13) | type t = Expect<Equal<typeof value, string | bigint>>;
  type t (line 27) | type t = Expect<Equal<typeof value, bigint>>;
  type t (line 31) | type t = Expect<Equal<typeof value, string | bigint>>;
  type t (line 43) | type t = Expect<Equal<typeof value, bigint>>;
  type t (line 47) | type t = Expect<Equal<typeof value, string | bigint>>;
  type t (line 59) | type t = Expect<Equal<typeof value, bigint>>;
  type t (line 63) | type t = Expect<Equal<typeof value, string | bigint>>;
  type t (line 75) | type t = Expect<Equal<typeof value, bigint>>;
  type t (line 79) | type t = Expect<Equal<typeof value, string | bigint>>;
  type t (line 91) | type t = Expect<Equal<typeof value, bigint>>;
  type t (line 95) | type t = Expect<Equal<typeof value, string | bigint>>;
  type t (line 107) | type t = Expect<Equal<typeof value, bigint>>;
  type t (line 111) | type t = Expect<Equal<typeof value, string | bigint>>;

FILE: tests/branded-nominal-types.test.ts
  type BrandedId (line 4) | type BrandedId = string & { __brand: 'brandId' };
  type FooBar (line 5) | type FooBar = { type: 'foo'; id: BrandedId; value: string } | { type: 'b...
  type State (line 6) | type State = {
  type Tagged (line 29) | type Tagged<Token> = { readonly [tag]: Token };
  type Opaque (line 30) | type Opaque<Type, Token = unknown> = Type & Tagged<Token>;
  type Branded (line 43) | interface Branded<key extends string> {
  type Brand (line 47) | type Brand<a, key extends string> = a & Branded<key>;
  type BrandId (line 48) | type BrandId = Brand<number, 'BrandId'>;

FILE: tests/build-many.test.ts
  type cases (line 7) | type cases = [

FILE: tests/chainable.test.ts
  type t (line 10) | type t = Expect<Equal<typeof value, string | undefined>>;
  type t (line 14) | type t = Expect<Equal<typeof value, number>>;
  type t (line 27) | type t = Expect<Equal<typeof value, string>>;
  type t (line 40) | type t = Expect<Equal<typeof value, number | undefined>>;
  type t (line 53) | type t = Expect<Equal<typeof value, string | undefined>>;
  type t (line 70) | type t = Expect<
  type t (line 86) | type t = Expect<
  type t (line 105) | type t = Expect<Equal<typeof value, number | undefined>>;
  type t (line 109) | type t = Expect<Equal<typeof value, string>>;
  type t (line 122) | type t = Expect<Equal<typeof value, number>>;
  type t (line 146) | type t = Expect<Equal<typeof value, number | undefined>>;
  type t (line 167) | type t = Expect<Equal<typeof value, bigint | undefined>>;
  type t (line 171) | type t = Expect<Equal<typeof value, string>>;
  type t (line 184) | type t = Expect<Equal<typeof value, bigint>>;
  type t (line 202) | type t = Expect<Equal<typeof value, bigint | undefined>>;
  type t (line 223) | type t = Expect<
  type t (line 245) | type t = Expect<

FILE: tests/deep-exclude.test.ts
  type Colors (line 11) | type Colors = 'pink' | 'purple' | 'red' | 'yellow' | 'blue';
  type cases (line 15) | type cases = [
  type cases (line 31) | type cases = [
  type cases (line 46) | type cases = [
  type cases (line 53) | type cases = [
  type x (line 64) | type x = DeepExclude<{ str: string | null | undefined }, { str: string }>;
  type xx (line 65) | type xx = DistributeMatchingUnions<
  type xxx (line 69) | type xxx = FindUnionsMany<
  type xxxx (line 73) | type xxxx = IsMatching<
  type xxxxx (line 77) | type xxxxx = FindUnions<
  type y (line 82) | type y = DeepExclude<
  type cases (line 87) | type cases = [
  type input (line 133) | type input = {
  type pattern (line 137) | type pattern = {
  type res1 (line 141) | type res1 = DeepExclude<input, pattern>;
  type test1 (line 142) | type test1 = Expect<
  type cases (line 150) | type cases = [
  type cases (line 182) | type cases = [
  type cases (line 190) | type cases = [
  type State (line 211) | type State = {};
  type Msg (line 212) | type Msg = [type: 'Login'] | [type: 'UrlChange', url: string];
  type Input (line 213) | type Input = [State, Msg];
  type cases (line 215) | type cases = [
  type res1 (line 246) | type res1 = DeepExclude<number[], [number, ...number[]]>;
  type test1 (line 247) | type test1 = Expect<Equal<res1, []>>;
  type res2 (line 249) | type res2 = DeepExclude<number[], []>;
  type test2 (line 250) | type test2 = Expect<Equal<res2, [number, ...number[]]>>;
  type res3 (line 252) | type res3 = DeepExclude<number[], [...number[], number]>;
  type test3 (line 253) | type test3 = Expect<Equal<res3, []>>;
  type res4 (line 255) | type res4 = DeepExclude<[number, ...number[]], [...number[], number]>;
  type test4 (line 257) | type test4 = Expect<Equal<res4, never>>;
  type res1 (line 261) | type res1 = DeepExclude<number[], [string, ...number[]]>;
  type test1 (line 262) | type test1 = Expect<Equal<res1, number[]>>;
  type res3 (line 264) | type res3 = DeepExclude<number[], [...string[], number]>;
  type test3 (line 265) | type test3 = Expect<Equal<res3, number[]>>;
  type res4 (line 268) | type res4 = DeepExclude<[number, ...string[]], [...number[], string]>;
  type test4 (line 269) | type test4 = Expect<Equal<res4, [number, ...string[]]>>;
  type cases (line 274) | type cases = [
  type res1 (line 284) | type res1 = DeepExclude<{ values: (1 | 2 | 3)[] }, { values: [] }>;
  type test1 (line 285) | type test1 = Expect<
  type cases (line 289) | type cases = [
  type cases (line 308) | type cases = [
  type cases (line 322) | type cases = [
  type cases (line 351) | type cases = [
  type cases (line 396) | type cases = [
  type cases (line 464) | type cases = [
  type cases (line 489) | type cases = [
  type Input (line 548) | type Input = readonly ['a' | 'b', 'c' | 'd'];
  type p (line 549) | type p = ['a', 'c'] | ['a', 'd'] | ['b', 'c'] | ['b', 'd'];
  type cases (line 551) | type cases = [
  type cases (line 563) | type cases = [
  type t (line 577) | type t = Expect<

FILE: tests/distribute-unions.test.ts
  type res1 (line 13) | type res1 = FindUnions<{ a: 1 | 2; b: 3 | 4; c: 6 | 7 }, { a: 1; b: 3 }>;
  type test1 (line 14) | type test1 = Expect<
  type res2 (line 45) | type res2 = FindUnions<
  type test2 (line 54) | type test2 = Expect<
  type res3 (line 97) | type res3 = FindUnions<
  type test3 (line 113) | type test3 = Expect<
  type res4 (line 181) | type res4 = FindUnions<
  type test4 (line 185) | type test4 = Expect<
  type res5 (line 227) | type res5 = FindUnions<
  type test5 (line 239) | type test5 = Expect<
  type cases (line 285) | type cases = [
  type res1 (line 430) | type res1 = FindUnions<readonly number[], readonly []>;
  type tes1 (line 431) | type tes1 = Expect<
  type res2 (line 451) | type res2 = FindUnions<[number], []>;
  type tes2 (line 452) | type tes2 = Expect<Equal<res2, []>>;
  type res3 (line 454) | type res3 = FindUnions<[number], [number, ...number[]]>;
  type tes3 (line 455) | type tes3 = Expect<Equal<res3, []>>;
  type res4 (line 457) | type res4 = FindUnions<[number], [...number[], number]>;
  type tes4 (line 458) | type tes4 = Expect<Equal<res4, []>>;
  type res5 (line 460) | type res5 = FindUnions<[number], [...number[], number]>;
  type tes5 (line 461) | type tes5 = Expect<Equal<res5, []>>;
  type res6 (line 463) | type res6 = FindUnions<readonly number[], readonly [number, ...number[]]>;
  type tes6 (line 464) | type tes6 = Expect<
  type res7 (line 484) | type res7 = FindUnions<readonly number[], readonly [...number[], number]>;
  type tes7 (line 485) | type tes7 = Expect<
  type res8 (line 505) | type res8 = FindUnions<
  type tes8 (line 509) | type tes8 = Expect<Equal<res8, []>>;
  type res9 (line 511) | type res9 = FindUnions<
  type tes9 (line 515) | type tes9 = Expect<Equal<res9, []>>;
  type cases (line 519) | type cases = [
  type cases (line 567) | type cases = [
  type cases (line 716) | type cases = [
  type cases (line 756) | type cases = [
  type cases (line 764) | type cases = [
  type cases (line 797) | type cases = [
  type res1 (line 845) | type res1 = DistributeMatchingUnions<[], []>;
  type test1 (line 846) | type test1 = Expect<Equal<res1, []>>;
  type cases (line 848) | type cases = [
  type X (line 868) | type X = 1 | 2 | 3 | 4 | 5 | 6 | 7;
  type cases (line 870) | type cases = [
  type cases (line 941) | type cases = [
  type cases (line 993) | type cases = [
  type cases (line 1026) | type cases = [

FILE: tests/exhaustive-fallback.test.ts
  type t (line 12) | type t = Expect<

FILE: tests/exhaustive-match.test.ts
  type Input (line 15) | type Input = 'a' | 'b' | 'c';
  type t (line 20) | type t = Expect<Equal<typeof x, 'b'>>;
  type t (line 34) | type t = Expect<Equal<typeof x, 'a'>>;
  type t (line 38) | type t = Expect<Equal<typeof x, 'b'>>;
  type t (line 46) | type t = Expect<Equal<typeof x, 'a'>>;
  type t (line 50) | type t = Expect<Equal<typeof x, 'b'>>;
  type t (line 54) | type t = Expect<Equal<typeof x, 'c'>>;
  type Input (line 61) | type Input = 1 | 2 | 3;
  type t (line 66) | type t = Expect<Equal<typeof x, 2>>;
  type t (line 80) | type t = Expect<Equal<typeof x, 1>>;
  type t (line 84) | type t = Expect<Equal<typeof x, 2>>;
  type t (line 92) | type t = Expect<Equal<typeof x, 1>>;
  type t (line 96) | type t = Expect<Equal<typeof x, 2>>;
  type t (line 100) | type t = Expect<Equal<typeof x, 3>>;
  type Input (line 107) | type Input =
  type Input (line 130) | type Input = [boolean, boolean];
  type letter (line 149) | type letter =
  type Input (line 177) | type Input =
  type t (line 199) | type t = Expect<Equal<typeof data, number>>;
  type t (line 204) | type t = Expect<Equal<typeof data, true>>;
  type t (line 208) | type t = Expect<Equal<typeof data, boolean>>;
  type Input (line 259) | type Input = [1, number] | ['two', string] | [3, boolean];
  type Input (line 288) | type Input =
  type Input (line 321) | type Input = ['two', Option<string>];
  type Input (line 357) | type Input = { value: 'a' | 'b' };
  type Input (line 376) | type Input =
  type Input (line 431) | type Input = Set<string> | Set<number>;
  type Input (line 446) | type Input = Set<string> | Set<number>;
  type Input (line 465) | type Input = Map<string, 1 | 2 | 3>;
  type X (line 495) | type X = 1 | 2 | 3 | 4 | 5 | 6 | 7;
  type t (line 575) | type t = Expect<Equal<typeof res, Option<string>>>;
  type Input (line 581) | type Input = { type: 'test' } | ['hello', Option<string>] | 'hello'[];
  type t (line 594) | type t = Expect<
  type Input (line 604) | type Input = { type: 'video'; duration: number };
  type t (line 621) | type t = Expect<Equal<typeof x, { x: 1 }>>;
  type t (line 625) | type t = Expect<Equal<typeof x, { x: 2 }>>;
  type t (line 629) | type t = Expect<Equal<typeof x, { x: 3 }>>;
  type t (line 670) | type t = Expect<Equal<typeof x, 2>>;
  type t (line 678) | type t = Expect<Equal<typeof x, 2>>;
  type t (line 686) | type t = Expect<Equal<typeof x, 1>>;
  type t (line 690) | type t = Expect<Equal<typeof x, 2>>;
  type t (line 694) | type t = Expect<Equal<typeof x, 3>>;
  type Input (line 702) | type Input =
  type Input (line 773) | type Input = { type: 3; data: number };
  type t (line 779) | type t = Expect<Equal<typeof data, number>>;
  type Input2 (line 784) | type Input2 = { type: 3; data: true } | 2;
  type t (line 787) | type t = Expect<Equal<typeof data, true>>;
  type FlagComponent (line 795) | type FlagComponent = { color: 'red' | 'white' | 'blue' };
  function checkFlagComponent (line 797) | function checkFlagComponent(component: FlagComponent) {
  type t (line 911) | type t = Expect<Equal<typeof x, { t: 'a'; x: any }>>;
  type Person (line 933) | type Person = {
  function withTypo (line 938) | function withTypo(person: Person) {
  function withoutTypo (line 966) | function withoutTypo(person: Person) {
  type Input (line 984) | type Input = string | Date | readonly string[];
  type Input (line 997) | type Input = { type?: 'one' } | { type: 'two' };
  type t (line 1028) | type t = Expect<Equal<typeof x, { type: undefined }>>;
  type t (line 1050) | type t = Expect<Equal<typeof x, { type?: undefined }>>;
  type t (line 1071) | type t = Expect<Equal<typeof x, { type: undefined }>>;

FILE: tests/extract-precise-value.test.ts
  type res1 (line 9) | type res1 = ExtractPreciseValue<
  type test1 (line 14) | type test1 = Expect<
  type cases (line 18) | type cases = [
  type cases (line 75) | type cases = [
  type cases (line 86) | type cases = [
  type cases (line 97) | type cases = [
  type cases (line 142) | type cases = [
  type Input (line 174) | type Input = { t: 'a'; data: 'string'; x: any } | { t: 'b' };
  type cases (line 176) | type cases = [
  type res1 (line 214) | type res1 = ExtractPreciseValue<
  type test1 (line 218) | type test1 = Expect<Equal<res1, string[]>>;
  type res2 (line 220) | type res2 = ExtractPreciseValue<
  type test2 (line 224) | type test2 = Expect<Equal<res2, { b: number; c: string }[]>>;
  type Input (line 230) | type Input =
  type cases (line 235) | type cases = [
  type Input (line 258) | type Input =
  type cases (line 268) | type cases = [
  type nonNullable (line 298) | type nonNullable = InvertPattern<NonNullablePattern, unknown>;
  type res1 (line 301) | type res1 = ExtractPreciseValue<{ a: string }, { b: nonNullable }>;
  type test1 (line 302) | type test1 = Expect<Equal<res1, never>>;
  type res2 (line 304) | type res2 = ExtractPreciseValue<
  type test2 (line 308) | type test2 = Expect<Equal<res2, { b: number }>>;
  type res3 (line 310) | type res3 = ExtractPreciseValue<
  type test3 (line 314) | type test3 = Expect<
  type res1 (line 320) | type res1 = ExtractPreciseValue<
  type test1 (line 324) | type test1 = Expect<Equal<res1, { b: {} }>>;
  type res1 (line 328) | type res1 = ExtractPreciseValue<{ a: number }, { b: { c: nonNullable } }>;
  type test1 (line 329) | type test1 = Expect<Equal<res1, never>>;
  type res2 (line 331) | type res2 = ExtractPreciseValue<
  type test2 (line 337) | type test2 = Expect<
  type BrandedId (line 351) | type BrandedId = string & { __brand: 'brandId' };
  type FooBar (line 353) | type FooBar =
  type cases (line 357) | type cases = [
  class A (line 386) | class A {
  class B (line 389) | class B {
  type cases (line 392) | type cases = [Expect<Equal<ExtractPreciseValue<A | B, A>, A>>];
  class FooError (line 396) | class FooError extends Error {
  class BazError (line 400) | class BazError extends Error {
  class ErrorWithOptionalKeys1 (line 404) | class ErrorWithOptionalKeys1 extends Error {
  class ErrorWithOptionalKeys2 (line 408) | class ErrorWithOptionalKeys2 extends Error {
  type cases (line 412) | type cases = [
  type res1 (line 436) | type res1 = ExtractPreciseValue<unknown[], [unknown, ...unknown[]]>;
  type t1 (line 437) | type t1 = Expect<Equal<res1, [unknown, ...unknown[]]>>;
  type res2 (line 439) | type res2 = ExtractPreciseValue<unknown[], [number, ...string[]]>;
  type t2 (line 440) | type t2 = Expect<Equal<res2, [number, ...string[]]>>;
  type res3 (line 442) | type res3 = ExtractPreciseValue<
  type t3 (line 446) | type t3 = Expect<Equal<res3, ['a', ...boolean[]]>>;
  type res4 (line 448) | type res4 = ExtractPreciseValue<
  type t4 (line 452) | type t4 = Expect<Equal<res4, ['a', ...(string | boolean)[]]>>;
  type res1 (line 456) | type res1 = ExtractPreciseValue<
  type t1 (line 460) | type t1 = Expect<Equal<res1, [unknown, unknown, ...unknown[]]>>;
  type res2 (line 462) | type res2 = ExtractPreciseValue<
  type t2 (line 466) | type t2 = Expect<Equal<res2, [number, boolean, ...string[]]>>;
  type res3 (line 468) | type res3 = ExtractPreciseValue<
  type t3 (line 472) | type t3 = Expect<Equal<res3, ['a', 2, ...boolean[]]>>;
  type res1 (line 476) | type res1 = ExtractPreciseValue<unknown[], [...unknown[], unknown]>;
  type t1 (line 477) | type t1 = Expect<Equal<res1, [...unknown[], unknown]>>;
  type res2 (line 479) | type res2 = ExtractPreciseValue<unknown[], [...string[], number]>;
  type t2 (line 480) | type t2 = Expect<Equal<res2, [...string[], number]>>;
  type res3 (line 482) | type res3 = ExtractPreciseValue<
  type t3 (line 486) | type t3 = Expect<Equal<res3, [...boolean[], 'a']>>;
  type res1 (line 489) | type res1 = ExtractPreciseValue<
  type t1 (line 493) | type t1 = Expect<Equal<res1, [...unknown[], unknown, unknown]>>;
  type res2 (line 495) | type res2 = ExtractPreciseValue<
  type t2 (line 499) | type t2 = Expect<Equal<res2, [...string[], number, boolean]>>;
  type res3 (line 501) | type res3 = ExtractPreciseValue<
  type t3 (line 505) | type t3 = Expect<Equal<res3, [...boolean[], 'a', true]>>;
  type res1 (line 508) | type res1 = ExtractPreciseValue<
  type t1 (line 512) | type t1 = Expect<Equal<res1, [unknown, ...unknown[], unknown]>>;
  type res2 (line 514) | type res2 = ExtractPreciseValue<
  type t2 (line 518) | type t2 = Expect<Equal<res2, [number, ...string[], boolean]>>;
  type res3 (line 520) | type res3 = ExtractPreciseValue<
  type t3 (line 524) | type t3 = Expect<Equal<res3, ['a', ...boolean[], 2]>>;
  type res1 (line 532) | type res1 = ExtractPreciseValue<
  type test1 (line 538) | type test1 = Expect<

FILE: tests/find-selected.test.ts
  type AnonymousSelectP (line 17) | type AnonymousSelectP = SelectP<symbols.anonymousSelectKey>;
  type res1 (line 22) | type res1 = FindSelected<
  type test1 (line 32) | type test1 = Expect<Equal<res1, { c: 3 }>>;
  type cases (line 34) | type cases = [
  type res1 (line 79) | type res1 = FindSelected<
  type test1 (line 83) | type test1 = Expect<Equal<res1, { state: State; event: Event[] }>>;
  type res2 (line 85) | type res2 = FindSelected<
  type test2 (line 89) | type test2 = Expect<Equal<res2, 1>>;
  type res3 (line 91) | type res3 = FindSelected<
  type test3 (line 95) | type test3 = Expect<Equal<res3, number[]>>;
  type res1 (line 99) | type res1 = FindSelected<
  type test1 (line 107) | type test1 = Expect<
  type res2 (line 111) | type res2 = FindSelected<
  type test2 (line 115) | type test2 = Expect<Equal<res2, 1>>;
  type res3 (line 117) | type res3 = FindSelected<
  type test3 (line 121) | type test3 = Expect<Equal<res3, 2>>;
  type res4 (line 123) | type res4 = FindSelected<
  type test4 (line 127) | type test4 = Expect<Equal<res4, number[]>>;
  type res1 (line 130) | type res1 = FindSelected<
  type test1 (line 134) | type test1 = Expect<Equal<res1, { state: State; event: Event[] }>>;
  type res2 (line 136) | type res2 = FindSelected<
  type test2 (line 140) | type test2 = Expect<Equal<res2, 1>>;
  type res3 (line 142) | type res3 = FindSelected<
  type test3 (line 146) | type test3 = Expect<Equal<res3, number[]>>;
  type res1 (line 149) | type res1 = FindSelected<
  type test1 (line 157) | type test1 = Expect<
  type res2 (line 161) | type res2 = FindSelected<
  type test2 (line 165) | type test2 = Expect<Equal<res2, 1>>;
  type res3 (line 167) | type res3 = FindSelected<
  type test3 (line 171) | type test3 = Expect<Equal<res3, 2>>;
  type res4 (line 173) | type res4 = FindSelected<
  type test4 (line 177) | type test4 = Expect<Equal<res4, number[]>>;
  type res1 (line 181) | type res1 = FindSelected<
  type test1 (line 189) | type test1 = Expect<
  type res2 (line 193) | type res2 = FindSelected<
  type test2 (line 197) | type test2 = Expect<Equal<res2, 1>>;
  type res3 (line 199) | type res3 = FindSelected<
  type test3 (line 203) | type test3 = Expect<Equal<res3, 2>>;
  type res4 (line 205) | type res4 = FindSelected<
  type test4 (line 209) | type test4 = Expect<Equal<res4, number[]>>;
  type res1 (line 213) | type res1 = FindSelected<
  type test1 (line 217) | type test1 = Expect<Equal<res1, number>>;
  type res2 (line 219) | type res2 = FindSelected<
  type test2 (line 223) | type test2 = Expect<Equal<res2, Event>>;
  type res1 (line 227) | type res1 = FindSelected<
  type test1 (line 231) | type test1 = Expect<Equal<res1, number>>;
  type res2 (line 233) | type res2 = FindSelected<
  type test2 (line 237) | type test2 = Expect<Equal<res2, State>>;
  type cases (line 242) | type cases = [
  type cases (line 274) | type cases = [
  type res1 (line 302) | type res1 = FindSelected<
  type res12 (line 307) | type res12 = FindSelected<
  type x (line 312) | type x = Extract<[1, 2], readonly any[]>;
  type test1 (line 313) | type test1 = Expect<Equal<res1, { c: 3 }>>;
  type res2 (line 314) | type res2 = FindSelected<
  type test2 (line 321) | type test2 = Expect<Equal<res2, { c: 3; d: string[] }>>;
  type cases (line 327) | type cases = [
  type cases (line 343) | type cases = [
  type Input (line 411) | type Input =
  type cases (line 423) | type cases = [
  type Input (line 444) | type Input = { type: 'text'; text: string; author: { name: string } };
  type cases (line 446) | type cases = [
  type p (line 479) | type p = {
  type value (line 506) | type value = {
  type t (line 516) | type t = Expect<Equal<FindSelected<value, p>, value>>;

FILE: tests/generics.test.ts
  type State (line 13) | type State<T> =
  type t (line 22) | type t = Expect<Equal<typeof x, { t: 'success'; value: T }>>;
  type t (line 26) | type t = Expect<Equal<typeof x, { t: 'error'; error: Error }>>;
  type t (line 30) | type t = Expect<Equal<typeof x, { t: 'loading' }>>;
  type t (line 42) | type t = Expect<Equal<typeof x, a[]>>;
  type t2 (line 43) | type t2 = Expect<Equal<typeof y, a[]>>;
  type State (line 50) | type State<T> = { t: 'success'; value: T } | { t: 'error'; error: Error };
  type t (line 55) | type t = Expect<Equal<typeof x, { t: 'success'; value: a }>>;
  type t2 (line 56) | type t2 = Expect<Equal<typeof y, { t: 'success'; value: b }>>;
  type t (line 60) | type t = Expect<Equal<typeof x, { t: 'success'; value: a }>>;
  type t2 (line 61) | type t2 = Expect<Equal<typeof y, { t: 'error'; error: Error }>>;
  type t (line 65) | type t = Expect<Equal<typeof x, { t: 'error'; error: Error }>>;
  type t2 (line 66) | type t2 = Expect<Equal<typeof y, State<b>>>;
  type t (line 88) | type t = Expect<
  type t (line 97) | type t = Expect<
  type test (line 113) | type test = Expect<
  type test (line 118) | type test = Expect<
  type test (line 123) | type test = Expect<
  type test (line 135) | type test = Expect<

FILE: tests/helpers.test.ts
  type cases (line 16) | type cases = [
  type cases (line 26) | type cases = [
  type cases (line 38) | type cases = [
  type cases (line 48) | type cases = [
  type cases (line 61) | type cases = [
  class B (line 78) | class B {}
  class A (line 79) | class A extends B {}
  type t (line 80) | type t = Expect<Equal<LeastUpperBound<A | B, B>, B>>;
  type x (line 86) | type x = IntersectObjects<
  type t (line 92) | type t = Expect<
  type t2 (line 105) | type t2 = Expect<
  type t3 (line 119) | type t3 = Expect<
  type t1 (line 134) | type t1 = IsReadonlyArray<readonly []>;
  type test1 (line 135) | type test1 = Expect<Equal<t1, true>>;
  type t2 (line 136) | type t2 = IsReadonlyArray<readonly number[]>;
  type test2 (line 137) | type test2 = Expect<Equal<t2, true>>;
  type t3 (line 138) | type t3 = IsReadonlyArray<readonly [number]>;
  type test3 (line 139) | type test3 = Expect<Equal<t3, true>>;
  type t4 (line 140) | type t4 = IsReadonlyArray<readonly [number, ...(readonly any[])]>;
  type test4 (line 141) | type test4 = Expect<Equal<t4, true>>;
  type t5 (line 142) | type t5 = IsReadonlyArray<readonly [...(readonly any[]), number]>;
  type test5 (line 143) | type test5 = Expect<Equal<t5, true>>;
  type t6 (line 145) | type t6 = IsReadonlyArray<[]>;
  type test6 (line 146) | type test6 = Expect<Equal<t6, false>>;
  type t7 (line 147) | type t7 = IsReadonlyArray<number[]>;
  type test7 (line 148) | type test7 = Expect<Equal<t7, false>>;
  type t8 (line 149) | type t8 = IsReadonlyArray<[number]>;
  type test8 (line 150) | type test8 = Expect<Equal<t8, false>>;
  type t9 (line 151) | type t9 = IsReadonlyArray<[number, ...any[]]>;
  type test9 (line 152) | type test9 = Expect<Equal<t9, false>>;
  type t10 (line 153) | type t10 = IsReadonlyArray<[...any[], number]>;
  type test10 (line 154) | type test10 = Expect<Equal<t10, false>>;

FILE: tests/infer.test.ts
  type QuizValue (line 13) | type QuizValue = P.infer<typeof QuizValue>;
  type expected1 (line 14) | type expected1 = 'initial' | 'correct' | 'incorrect';
  type test1 (line 15) | type test1 = Expect<Equal<QuizValue, expected1>>;
  type QuizState (line 17) | type QuizState = P.infer<typeof QuizState>;
  type expected2 (line 18) | type expected2 = {
  type test2 (line 22) | type test2 = Expect<Equal<QuizState, expected2>>;

FILE: tests/instance-of.test.ts
  class A (line 4) | class A {
  class B (line 7) | class B {
  type t (line 16) | type t = Expect<Equal<typeof x, A>>;
  type t (line 20) | type t = Expect<Equal<typeof x, B>>;
  type Input (line 30) | type Input = { value: A | B };
  type t (line 36) | type t = Expect<Equal<typeof a, { value: A }>>;
  type t (line 40) | type t = Expect<Equal<typeof b, { value: B }>>;
  class FooError (line 49) | class FooError extends Error {
    method constructor (line 50) | constructor(public foo: string) {
  class BazError (line 55) | class BazError extends Error {
    method constructor (line 56) | constructor(public baz: string) {
  type Input (line 61) | type Input = FooError | BazError | Error;
  class A (line 76) | class A extends Abstract {}
  class B (line 77) | class B extends Abstract {}
  type t (line 82) | type t = Expect<Equal<typeof x, A | B>>;

FILE: tests/intersection-and-union.test.ts
  type A (line 5) | type A = {
    method constructor (line 730) | constructor(public foo: 'bar' | 'baz') {}
  type B (line 13) | type B = {
    method constructor (line 734) | constructor(public str: string) {}
  type Input (line 21) | type Input = A | B;
  class Child1 (line 25) | class Child1 extends Parent {
    method constructor (line 26) | constructor(public a?: Parent, public b?: Parent) {
  class Child2 (line 31) | class Child2 extends Parent {
    method constructor (line 32) | constructor(public a?: Parent, public b?: Parent) {
  type t (line 49) | type t = Expect<
  type t (line 68) | type t = Expect<
  type t (line 87) | type t = Expect<Equal<typeof x, A>>;
  type C (line 95) | type C = {
  type Input (line 103) | type Input =
  type t (line 111) | type t = Expect<
  type t (line 120) | type t = Expect<Equal<typeof x, C>>;
  type t (line 128) | type t = Expect<
  type t (line 137) | type t = Expect<
  type t (line 151) | type t = Expect<
  type Country (line 166) | type Country = 'France' | 'Germany' | 'Spain' | 'USA';
  type t (line 190) | type t = Expect<
  type t (line 231) | type t = Expect<
  type t (line 244) | type t = Expect<
  type t (line 294) | type t = Expect<Equal<typeof x, number>>;
  type t (line 314) | type t = Expect<Equal<typeof x, number>>;
  type t (line 337) | type t = Expect<Equal<typeof x, number>>;
  type Input (line 350) | type Input = {
  type t (line 366) | type t = Expect<
  type Input (line 384) | type Input = {
  type t (line 400) | type t = Expect<
  type t (line 417) | type t = Expect<Equal<typeof x, number | undefined>>;
  type Input (line 438) | type Input = {
  type t (line 447) | type t = Expect<
  type t (line 453) | type t = Expect<
  type Input (line 469) | type Input = {
  type t (line 479) | type t = Expect<
  type t (line 495) | type t = Expect<
  type Input (line 532) | type Input = {
  type t (line 542) | type t = Expect<
  type t (line 557) | type t = Expect<
  type Input (line 593) | type Input =
  type t (line 614) | type t = Expect<
  type t (line 639) | type t = Expect<
  type Input (line 672) | type Input = {
  type t (line 683) | type t = Expect<
  type t (line 698) | type t = Expect<
  type t (line 719) | type t = Expect<
  class A (line 729) | class A {
    method constructor (line 730) | constructor(public foo: 'bar' | 'baz') {}
  class B (line 733) | class B {
    method constructor (line 734) | constructor(public str: string) {}
  type t (line 743) | type t = Expect<Equal<typeof prop, A & { foo: 'bar' }>>;
  type t (line 751) | type t = Expect<Equal<typeof prop, A & { foo: 'baz' }>>;
  type t (line 759) | type t = Expect<Equal<typeof prop, B>>;

FILE: tests/invert-pattern.test.ts
  type pattern1 (line 11) | type pattern1 = [
  type inverted1 (line 15) | type inverted1 = InvertPattern<pattern1, unknown>;
  type test1 (line 17) | type test1 = Expect<Equal<inverted1, ['Hello', ...number[]]>>;
  type pattern2 (line 19) | type pattern2 = [
  type inverted2 (line 23) | type inverted2 = InvertPattern<pattern2, unknown>;
  type test2 (line 25) | type test2 = Expect<Equal<inverted2, [unknown, ...unknown[]]>>;
  type pattern3 (line 27) | type pattern3 = [
  type inverted3 (line 31) | type inverted3 = InvertPattern<pattern3, unknown>;
  type test3 (line 33) | type test3 = Expect<Equal<inverted3, [string, ...number[]]>>;
  type pattern6 (line 35) | type pattern6 = {
  type input6 (line 41) | type input6 = unknown;
  type inverted6 (line 42) | type inverted6 = InvertPattern<pattern6, input6>;
  type test6 (line 44) | type test6 = Expect<Equal<inverted6, { key: [string, ...string[]] }>>;
  type pattern1 (line 48) | type pattern1 = [
  type inverted1 (line 53) | type inverted1 = InvertPattern<pattern1, unknown>;
  type test1 (line 55) | type test1 = Expect<Equal<inverted1, ['Hello', 7, ...number[]]>>;
  type pattern2 (line 57) | type pattern2 = [
  type inverted2 (line 62) | type inverted2 = InvertPattern<pattern2, unknown>;
  type test2 (line 64) | type test2 = Expect<Equal<inverted2, [unknown, unknown, ...unknown[]]>>;
  type pattern3 (line 66) | type pattern3 = [
  type inverted3 (line 71) | type inverted3 = InvertPattern<pattern3, unknown>;
  type test3 (line 73) | type test3 = Expect<Equal<inverted3, [string, boolean, ...number[]]>>;
  type pattern1 (line 76) | type pattern1 = [
  type inverted1 (line 80) | type inverted1 = InvertPattern<pattern1, unknown>;
  type test1 (line 82) | type test1 = Expect<Equal<inverted1, [...number[], 'Hello']>>;
  type pattern2 (line 84) | type pattern2 = [
  type inverted2 (line 88) | type inverted2 = InvertPattern<pattern2, unknown>;
  type test2 (line 90) | type test2 = Expect<Equal<inverted2, [...unknown[], unknown]>>;
  type pattern3 (line 92) | type pattern3 = [
  type inverted3 (line 96) | type inverted3 = InvertPattern<pattern3, unknown>;
  type test3 (line 98) | type test3 = Expect<Equal<inverted3, [...number[], string]>>;
  type pattern1 (line 101) | type pattern1 = [
  type inverted1 (line 106) | type inverted1 = InvertPattern<pattern1, unknown>;
  type test1 (line 108) | type test1 = Expect<Equal<inverted1, [...number[], 'Hello', 7]>>;
  type pattern2 (line 110) | type pattern2 = [
  type inverted2 (line 115) | type inverted2 = InvertPattern<pattern2, unknown>;
  type test2 (line 117) | type test2 = Expect<Equal<inverted2, [...unknown[], unknown, unknown]>>;
  type pattern3 (line 119) | type pattern3 = [
  type inverted3 (line 124) | type inverted3 = InvertPattern<pattern3, unknown>;
  type test3 (line 126) | type test3 = Expect<Equal<inverted3, [...number[], string, boolean]>>;
  type pattern1 (line 129) | type pattern1 = [
  type inverted1 (line 134) | type inverted1 = InvertPattern<pattern1, unknown>;
  type test1 (line 136) | type test1 = Expect<Equal<inverted1, [7, ...number[], 'Hello']>>;
  type pattern2 (line 138) | type pattern2 = [
  type inverted2 (line 143) | type inverted2 = InvertPattern<pattern2, unknown>;
  type test2 (line 145) | type test2 = Expect<Equal<inverted2, [unknown, ...unknown[], unknown]>>;
  type pattern3 (line 147) | type pattern3 = [
  type inverted3 (line 152) | type inverted3 = InvertPattern<pattern3, unknown>;
  type test3 (line 154) | type test3 = Expect<Equal<inverted3, [string, ...number[], boolean]>>;
  type pattern1 (line 158) | type pattern1 = [
  type inverted1 (line 165) | type inverted1 = InvertPattern<pattern1, undefined>;
  type test1 (line 167) | type test1 = Expect<
  type pattern2 (line 171) | type pattern2 = [
  type inverted2 (line 178) | type inverted2 = InvertPattern<pattern2, undefined>;
  type test2 (line 180) | type test2 = Expect<
  type pattern3 (line 184) | type pattern3 = [
  type inverted3 (line 191) | type inverted3 = InvertPattern<pattern3, undefined>;
  type test3 (line 193) | type test3 = Expect<
  type cases (line 202) | type cases = [
  type res1 (line 229) | type res1 = InvertPatternForExclude<
  type test1 (line 233) | type test1 = Expect<Equal<res1, Readonly<{ a: string }>>>;
  type res1 (line 238) | type res1 = InvertPatternForExclude<
  type test1 (line 242) | type test1 = Expect<Equal<res1, [1, 2]>>;
  type res1 (line 246) | type res1 = InvertPatternForExclude<
  type test1 (line 250) | type test1 = Expect<Equal<res1, readonly [[readonly [1, 2]]]>>;
  type OptionalPattern (line 255) | type OptionalPattern<a> = Matcher<unknown, a, 'optional'>;
  type input (line 258) | type input = { key?: 'a' | 'b' };
  type pattern (line 259) | type pattern = { key: OptionalPattern<'a'> };
  type inverted (line 260) | type inverted = InvertPatternForExclude<pattern, input>;
  type cases (line 262) | type cases = [
  type x (line 274) | type x = InvertPatternForExclude<
  type cases (line 278) | type cases = [
  type input (line 284) | type input = { key?: 'a' | 'b' };
  type pattern (line 285) | type pattern = { key: OptionalPattern<'a'> };
  type inverted (line 286) | type inverted = InvertPatternForExclude<pattern, input>;
  type cases (line 288) | type cases = [
  type pattern1 (line 303) | type pattern1 = ['Hello', ...Matcher<any, GuardP<unknown, 2>, 'array'>[]];
  type input1 (line 304) | type input1 = { a: string; b: number } | [string, ...number[]];
  type inverted1 (line 305) | type inverted1 = InvertPatternForExclude<pattern1, input1>;
  type test1 (line 306) | type test1 = Expect<Equal<inverted1, ['Hello', ...2[]]>>;
  type pattern2 (line 308) | type pattern2 = ['Hello', ...Matcher<any, GuardP<unknown, 2>, 'array'>[]];
  type input2 (line 309) | type input2 = [string, ...number[]];
  type inverted2 (line 310) | type inverted2 = InvertPatternForExclude<pattern2, input2>;
  type test2 (line 311) | type test2 = Expect<Equal<inverted2, ['Hello', ...2[]]>>;
  type pattern3 (line 313) | type pattern3 = [...Matcher<any, GuardP<unknown, 2>, 'array'>[]];
  type input3 (line 314) | type input3 = [...number[]];
  type inverted3 (line 315) | type inverted3 = InvertPatternForExclude<pattern3, input3>;
  type test3 (line 316) | type test3 = Expect<Equal<inverted3, [...2[]]>>;
  type pattern4 (line 318) | type pattern4 = readonly [
  type input4 (line 322) | type input4 = [string | number, ...(string | number)[]];
  type inverted4 (line 323) | type inverted4 = InvertPatternForExclude<pattern4, input4>;
  type test4 (line 325) | type test4 = Expect<Equal<inverted4, [unknown, ...(string | number)[]]>>;
  type pattern5 (line 327) | type pattern5 = ArrayP<unknown, unknown>;
  type input5 (line 328) | type input5 = (string | number)[];
  type inverted5 (line 329) | type inverted5 = InvertPatternForExclude<pattern5, input5>;
  type test5 (line 330) | type test5 = Expect<Equal<inverted5, (string | number)[]>>;
  type pattern1 (line 334) | type pattern1 = [
  type input1 (line 339) | type input1 = { a: string; b: number } | [string, number, ...number[]];
  type inverted1 (line 340) | type inverted1 = InvertPatternForExclude<pattern1, input1>;
  type test1 (line 341) | type test1 = Expect<Equal<inverted1, ['Hello', 10, ...2[]]>>;
  type pattern1 (line 344) | type pattern1 = [
  type input1 (line 348) | type input1 = { a: string; b: number } | [...number[], string];
  type inverted1 (line 349) | type inverted1 = InvertPatternForExclude<pattern1, input1>;
  type test1 (line 350) | type test1 = Expect<Equal<inverted1, [...number[], 'Hello']>>;
  type pattern1 (line 353) | type pattern1 = [
  type input1 (line 358) | type input1 = { a: string; b: number } | [...number[], string, boolean];
  type inverted1 (line 359) | type inverted1 = InvertPatternForExclude<pattern1, input1>;
  type test1 (line 360) | type test1 = Expect<Equal<inverted1, [...number[], 'Hello', true]>>;
  type pattern1 (line 363) | type pattern1 = [
  type input1 (line 368) | type input1 = { a: string; b: number } | [string, ...number[], boolean];
  type inverted1 (line 369) | type inverted1 = InvertPatternForExclude<pattern1, input1>;
  type test1 (line 370) | type test1 = Expect<Equal<inverted1, ['Hello', ...number[], true]>>;
  type input (line 377) | type input = { sex: 'a' | 'b'; age: 'c' | 'd' };
  type pattern (line 378) | type pattern = Readonly<{ sex: 'a'; unknownKey: 'c' }>;
  type inverted (line 379) | type inverted = InvertPatternForExclude<pattern, input>;
  type cases (line 381) | type cases = [Expect<Equal<inverted, pattern>>];
  type input (line 387) | type input = { sex: 'a' | 'b'; age: 'c' | 'd' };
  type pattern (line 388) | type pattern = Pattern<input>;
  type inverted (line 389) | type inverted = InvertPattern<pattern, input>;
  type test1 (line 391) | type test1 = Expect<Equal<inverted, never>>;
  type input (line 395) | type input = { sex: 'a' | 'b'; age: 'c' | 'd' };
  type pattern (line 396) | type pattern = Pattern<input>;
  type inverted (line 397) | type inverted = InvertPatternForExclude<pattern, input>;
  type test1 (line 399) | type test1 = Expect<Equal<inverted, never>>;

FILE: tests/is-matching.test.ts
  type t (line 17) | type t = Expect<
  type t (line 46) | type t = Expect<
  type Pizza (line 101) | type Pizza = { type: 'pizza'; topping: string };
  type Sandwich (line 102) | type Sandwich = { type: 'sandwich'; condiments: string[] };
  type Food (line 103) | type Food = Pizza | Sandwich;
  type t (line 111) | type t = Expect<Equal<typeof food, Pizza>>;
  type t (line 117) | type t = Expect<Equal<typeof food, Pizza>>;
  type t (line 140) | type t = Expect<
  type t (line 152) | type t = Expect<Equal<typeof food, Food & { unknownProp: Error }>>;
  type Input (line 157) | type Input = { someProperty: string[] } | { this: 'is a string' };
  type t (line 162) | type t = Expect<Equal<typeof input.someProperty, string[]>>;

FILE: tests/large-exhaustive.test.ts
  type LargeObject (line 6) | type LargeObject<T> = Compute<{
  type test1 (line 80) | type test1 = Expect<Not<Equal<typeof x, never>>>;
  type test2 (line 81) | type test2 = Expect<Not<Equal<typeof x, unknown>>>;
  type test3 (line 82) | type test3 = Expect<Not<Equal<typeof x, any>>>;
  type DeepObject (line 123) | type DeepObject = {
  type States (line 156) | type States = 'idle' | 'loading' | 'success' | 'error' | 'partial_result';
  type input (line 170) | type input = typeof input;

FILE: tests/lists.test.ts
  type t (line 13) | type t = Expect<Equal<typeof x, []>>;
  type t (line 17) | type t = Expect<Equal<typeof blogs, { id: number; title: string }[]>>;
  type t (line 24) | type t = Expect<Equal<typeof x, 20>>;
  type Input (line 44) | type Input = readonly {
  type t (line 69) | type t = Expect<

FILE: tests/maps.test.ts
  type t (line 21) | type t = Expect<Equal<typeof res, { name: string }>>;
  type t (line 35) | type t = Expect<Equal<typeof res, boolean>>;

FILE: tests/matcher-protocol.test.ts
  type SomeValue (line 5) | type SomeValue<T> = T extends Some<infer V> ? V : never;
  type SomeNarrowFn (line 7) | interface SomeNarrowFn extends P.unstable_Fn {
  class Some (line 11) | class Some<const T> {
    method constructor (line 12) | constructor(public value: T) {}
  method [P.matcher] (line 14) | static [P.matcher](): P.unstable_Matcher<SomeNarrowFn> {
  method [P.matcher] (line 22) | [P.matcher](): P.unstable_Matcher<
  class None (line 37) | class None {
    method constructor (line 39) | constructor() {
  method [P.matcher] (line 42) | static [P.matcher](): P.unstable_Matcher<None> {
  type Option (line 50) | type Option<T> = Some<T> | None;
  type t (line 57) | type t = Expect<Equal<typeof value, { option: Some<7> }>>;
  type t (line 61) | type t = Expect<Equal<typeof value, { option: Some<12> }>>;
  type t (line 73) | type t = Expect<Equal<typeof some, Some<number>>>;
  type t (line 83) | type t = Expect<Equal<typeof x, { option: Some<number | string> }>>;
  type t (line 87) | type t = Expect<Equal<typeof x, { option: None }>>;
  type t (line 99) | type t = Expect<Equal<typeof some, Some<10>>>;
  type t (line 111) | type t = Expect<Equal<typeof some, Some<number>>>;
  type t (line 117) | type t = Expect<Equal<typeof some, Some<number | string>>>;
  type t (line 120) | type t = Expect<Equal<typeof none, None>>;

FILE: tests/multiple-patterns.test.ts
  type t (line 14) | type t = Expect<
  type t (line 26) | type t = Expect<
  type t (line 54) | type t = Expect<
  type t (line 66) | type t = Expect<
  type Country (line 94) | type Country = 'France' | 'Germany' | 'Spain' | 'USA';
  type Input (line 126) | type Input =
  type t (line 140) | type t = Expect<Equal<typeof x, null | undefined>>;
  type t (line 144) | type t = Expect<Equal<typeof x, boolean | number | string>>;
  type t (line 153) | type t = Expect<
  type t (line 167) | type t = Expect<Equal<typeof x, [false, 2]>>;
  type t (line 171) | type t = Expect<Equal<typeof x, [false, number]>>;
  type t (line 175) | type t = Expect<Equal<typeof x, [true, number]>>;
  type t (line 230) | type t = Expect<Equal<typeof arr, number[]>>;
  type t (line 236) | type t = Expect<Equal<typeof arr, number[]>>;
  type t (line 242) | type t = Expect<Equal<typeof arr, number[]>>;

FILE: tests/narrow.test.ts
  type Input (line 6) | type Input = ['a' | 'b' | 'c', 'a' | 'b' | 'c'];
  type Narrowed (line 9) | type Narrowed = P.narrow<Input, typeof Pattern>;
  type test (line 11) | type test = Expect<Equal<Narrowed, ['a', 'a' | 'b']>>;
  type test (line 22) | type test = Expect<Equal<typeof prop, string>>;
  type test (line 33) | type test = Expect<Equal<typeof prop, 1 | 3>>;

FILE: tests/nesting.test.ts
  type Post (line 7) | type Post = {
  type Video (line 12) | type Video = { type: 'video'; id: number; content: { src: string } };
  type t (line 25) | type t = Expect<
  type t (line 50) | type t = Expect<Equal<typeof res, number>>;

FILE: tests/not.test.ts
  type t (line 10) | type t = Expect<Equal<typeof x, unknown>>;
  type t (line 14) | type t = Expect<Equal<typeof x, unknown>>;
  type DS (line 24) | type DS = { x: string | number; y: string | number };
  type t (line 28) | type t = Expect<Equal<typeof x, { x: number; y: number }>>;
  type t (line 45) | type t = Expect<Equal<typeof x, 'two'>>;
  type t (line 49) | type t = Expect<Equal<typeof x, 'one'>>;
  type t (line 65) | type t = Expect<Equal<typeof x, { key: 'two' }>>;
  type t (line 69) | type t = Expect<Equal<typeof x, { key: 'one' }>>;
  type Input (line 79) | type Input =
  type t (line 88) | type t = Expect<Equal<typeof x, { type: 'error' }>>;
  type t (line 92) | type t = Expect<Equal<typeof x, { type: 'success' }>>;
  type t (line 129) | type t = Expect<Equal<typeof str, string>>;
  type t (line 134) | type t = Expect<Equal<typeof str, null | undefined>>;
  type t (line 146) | type t = Expect<Equal<typeof x, { str: any }>>;
  type t (line 168) | type t = Expect<
  type Input (line 200) | type Input =
  type Input (line 236) | type Input =

FILE: tests/numbers.test.ts
  type t (line 8) | type t = Expect<Equal<typeof v, 1>>;
  type t (line 12) | type t = Expect<Equal<typeof v, 2>>;
  type t (line 17) | type t = Expect<Equal<typeof res, number>>;
  type t (line 64) | type t = Expect<Equal<typeof value, number>>;
  type t (line 68) | type t = Expect<Equal<typeof value, string | number>>;
  type t (line 82) | type t = Expect<Equal<typeof value, number>>;
  type t (line 86) | type t = Expect<Equal<typeof value, string | number | bigint>>;
  type t (line 98) | type t = Expect<Equal<typeof value, number>>;
  type t (line 102) | type t = Expect<Equal<typeof value, string | number | bigint>>;
  type t (line 114) | type t = Expect<Equal<typeof value, number>>;
  type t (line 118) | type t = Expect<Equal<typeof value, string | number | bigint>>;
  type t (line 130) | type t = Expect<Equal<typeof value, number>>;
  type t (line 134) | type t = Expect<Equal<typeof value, string | number | bigint>>;
  type t (line 146) | type t = Expect<Equal<typeof value, number>>;
  type t (line 150) | type t = Expect<Equal<typeof value, string | number | bigint>>;
  type t (line 162) | type t = Expect<Equal<typeof value, number>>;
  type t (line 166) | type t = Expect<Equal<typeof value, string | number | bigint>>;
  type t (line 178) | type t = Expect<Equal<typeof value, number>>;
  type t (line 182) | type t = Expect<Equal<typeof value, string | number | bigint>>;
  type t (line 195) | type t = Expect<Equal<typeof value, number>>;
  type t (line 199) | type t = Expect<Equal<typeof value, string | number | bigint>>;

FILE: tests/objects.test.ts
  type Input (line 9) | type Input = { [symbolA]: { [symbolB]: 'foo' | 'bar' } };
  type t (line 15) | type t = Expect<Equal<typeof value, 'foo'>>;
  type t (line 24) | type t = Expect<Equal<typeof value, 'bar'>>;
  type t (line 42) | type t = Expect<Equal<typeof sel, { [symbolB]: 'foo' | 'bar' }>>;
  type t (line 55) | type t = Expect<Equal<typeof sel, Input>>;
  type t (line 69) | type t = Expect<Equal<typeof sel, Input>>;
  type t (line 80) | type t = Expect<Equal<typeof sel, Input>>;
  type Vector1 (line 93) | type Vector1 = { x: number };
  type Vector2 (line 94) | type Vector2 = { x: number; y: number };
  type Vector3 (line 95) | type Vector3 = {
  type Vector (line 100) | type Vector = Vector1 | Vector2 | Vector3;
  type t (line 107) | type t = Expect<Equal<typeof x, { x: 1; y: 1; z: 1 }>>;
  type t (line 111) | type t = Expect<
  type t (line 117) | type t = Expect<

FILE: tests/optional-props.test.ts
  type Post (line 6) | type Post = {
  type t (line 18) | type t = Expect<Equal<typeof x, { type: 'post'; id: 2; body: string }>>;
  type t (line 22) | type t = Expect<
  type t (line 28) | type t = Expect<Equal<typeof x, Post>>;
  type Foo (line 39) | type Foo =
  type t (line 47) | type t = Expect<Equal<typeof id, string>>;
  type t (line 52) | type t = Expect<Equal<typeof id, string | undefined>>;
  type t (line 57) | type t = Expect<Equal<typeof id, string | undefined>>;
  type t (line 61) | type t = Expect<Equal<typeof id, string | undefined>>;
  type SomeEnum (line 73) | enum SomeEnum {
  type SomeObject (line 78) | type SomeObject = {
  type t (line 91) | type t = Expect<

FILE: tests/optional.test.ts
  type Input (line 6) | type Input = { a?: 'cool' } | { b: 'lol' };
  type t (line 14) | type t = Expect<Equal<typeof x, { a?: 'cool' | undefined }>>;
  type Input (line 25) | type Input = { a?: { name: string; age: number } } | { b: '' };
  type t (line 30) | type t = Expect<
  type Input (line 48) | type Input =
  type t (line 57) | type t = Expect<Equal<typeof x, string | undefined>>;
  type t (line 63) | type t = Expect<
  type t (line 72) | type t = Expect<Equal<typeof x, 'test' | undefined>>;
  type t (line 78) | type t = Expect<
  type t (line 96) | type t = Expect<Equal<typeof x, string | undefined>>;
  type t (line 100) | type t = Expect<Equal<typeof x, 'test' | undefined>>;
  type Input (line 110) | type Input = { a?: { name: string; age: number } } | { b: 'b' };
  type t1 (line 119) | type t1 = Expect<Equal<typeof name, string | undefined>>;
  type t2 (line 120) | type t2 = Expect<Equal<typeof age, number | undefined>>;
  type Input (line 132) | type Input =
  type t (line 150) | type t = Expect<
  type t (line 166) | type t = Expect<Equal<typeof x, { p: string | undefined }>>;
  type t (line 176) | type t = Expect<Equal<typeof src, number | undefined>>;
  type t (line 186) | type t = Expect<Equal<typeof p, string | undefined>>;
  type Input (line 195) | type Input = { maybeList?: { text: string }[] };
  type t (line 200) | type t = Expect<Equal<typeof x, string[] | undefined>>;

FILE: tests/output-type.test.ts
  type o1 (line 15) | type o1 = Expect<Equal<ReturnType<typeof f>, string>>;
  type o2 (line 24) | type o2 = Expect<Equal<ReturnType<typeof f2>, { x: string }>>;
  type o3 (line 33) | type o3 = Expect<Equal<ReturnType<typeof f3>, (number | null)[]>>;
  type o1 (line 43) | type o1 = Expect<Equal<ReturnType<typeof f1>, (number | null)[]>>;
  type o1 (line 56) | type o1 = Expect<Equal<ReturnType<typeof f1>, State>>;
  type o1 (line 69) | type o1 = Expect<Equal<ReturnType<typeof f>, string>>;
  type o2 (line 78) | type o2 = Expect<Equal<ReturnType<typeof f2>, { x: string }>>;
  type o3 (line 87) | type o3 = Expect<Equal<ReturnType<typeof f3>, (number | null)[]>>;
  type o1 (line 97) | type o1 = Expect<Equal<ReturnType<typeof f1>, (number | null)[]>>;
  type o1 (line 110) | type o1 = Expect<Equal<ReturnType<typeof f1>, State>>;
  type o1 (line 123) | type o1 = Expect<Equal<ReturnType<typeof f>, string>>;
  type o2 (line 132) | type o2 = Expect<Equal<ReturnType<typeof f2>, { x: string }>>;
  type o3 (line 141) | type o3 = Expect<Equal<ReturnType<typeof f3>, (number | null)[]>>;
  type o1 (line 151) | type o1 = Expect<Equal<ReturnType<typeof f1>, (number | null)[]>>;
  type o1 (line 164) | type o1 = Expect<Equal<ReturnType<typeof f1>, State>>;

FILE: tests/pattern.test.ts
  type ExtendsPattern (line 5) | type ExtendsPattern<a, p extends P.Pattern<a>> = true;
  type cases (line 9) | type cases = [
  type res1 (line 18) | type res1 = P.Pattern<{ kind: 'some'; value: number } | { kind: 'none' }>;
  type test1 (line 20) | type test1 = Expect<
  type t (line 39) | type t = P.Pattern<
  type t1 (line 43) | type t1 = Expect<
  type t2 (line 61) | type t2 = Expect<
  type t3 (line 77) | type t3 = Expect<
  type res4 (line 95) | type res4 = P.Pattern<{ name: string; age: number } | [type: 'Hello']>;
  type t4 (line 97) | type t4 = Expect<

FILE: tests/primitive-values.test.ts
  type t (line 11) | type t = Expect<Equal<typeof x, true>>;
  type t (line 15) | type t = Expect<Equal<typeof x, false>>;
  type t (line 19) | type t = Expect<Equal<typeof x, null>>;
  type t (line 23) | type t = Expect<Equal<typeof x, undefined>>;
  type t (line 27) | type t = Expect<Equal<typeof x, symbol>>;
  type t (line 31) | type t = Expect<Equal<typeof x, 'hello'>>;
  type t (line 35) | type t = Expect<Equal<typeof x, 1>>;
  type t (line 39) | type t = Expect<Equal<typeof x, bigint>>;
  type t (line 43) | type t = Expect<Equal<typeof x, 2>>;
  type t (line 54) | type t = Expect<Equal<typeof x, boolean>>;
  type t (line 58) | type t = Expect<Equal<typeof x, null | undefined>>;
  type t (line 62) | type t = Expect<Equal<typeof x, symbol>>;
  type t (line 66) | type t = Expect<Equal<typeof x, string>>;
  type t (line 70) | type t = Expect<Equal<typeof x, number>>;
  type t (line 74) | type t = Expect<Equal<typeof x, bigint>>;

FILE: tests/readonly.test.ts
  type t (line 10) | type t = Expect<Equal<typeof x, readonly ['a', 'c']>>;
  type t (line 14) | type t = Expect<Equal<typeof x, readonly ['a', 'd']>>;
  type t (line 18) | type t = Expect<Equal<typeof x, readonly ['b', 'c']>>;
  type t (line 22) | type t = Expect<Equal<typeof x, readonly ['b', 'd']>>;
  type t (line 34) | type t = Expect<Equal<typeof x, Readonly<{ t: 'a'; x: number }>>>;
  type t (line 38) | type t = Expect<Equal<typeof x, Readonly<{ t: 'b'; x: string }>>>;
  type t (line 52) | type t = Expect<Equal<typeof x, { t: 'a'; x: [2, 'hello', 2] }>>;
  type t (line 56) | type t = Expect<Equal<typeof x, { t: 'a'; x: [2, 'hello', 2] }>>;
  type t (line 60) | type t = Expect<
  type t (line 69) | type t = Expect<Equal<typeof x, Readonly<{ t: 'b'; x: string }>>>;
  type t (line 79) | type t = Expect<Equal<typeof x, readonly []>>;

FILE: tests/real-world.test.ts
  type t (line 18) | type t = Expect<
  type t (line 33) | type t = Expect<Equal<typeof q, string>>;
  type t (line 55) | type t = Expect<Equal<typeof format, 'timeseries' | 'scalar'>>;
  type t2 (line 56) | type t2 = Expect<Equal<typeof dataSource, 'metrics' | 'events'>>;

FILE: tests/record.test.ts
  type t (line 87) | type t = Expect<
  type t (line 109) | type t = Expect<
  type Data (line 158) | type Data = {
  type t (line 168) | type t = Expect<Equal<typeof x, Data>>;
  type t (line 186) | type t = Expect<Equal<typeof value, Record<number, string>>>;
  type t (line 198) | type t = Expect<Equal<typeof value, { readonly a: 1 }>>;
  type OptionalRecord (line 206) | type OptionalRecord = {
  type t (line 218) | type t = Expect<
  type t (line 247) | type t = Expect<
  type t (line 270) | type t = Expect<Equal<typeof value, Record<symbol, number>>>;
  type Input (line 280) | type Input = { key?: Record<string, number> };
  type t (line 286) | type t = Expect<
  type t (line 302) | type t = Expect<Equal<typeof value, Record<number, string>>>;
  type t (line 313) | type t = Expect<Equal<typeof value, Record<1, string>>>;
  type t (line 324) | type t = Expect<Equal<typeof value, Record<1 | 2, string>>>;
  type t (line 335) | type t = Expect<Equal<typeof value, Record<string, string>>>;
  type t (line 348) | type t = Expect<Equal<typeof value, string[]>>;
  type t (line 360) | type t = Expect<Equal<typeof value, number[]>>;
  type t (line 377) | type t = Expect<Equal<typeof value, string[]>>;
  type t (line 405) | type t = Expect<Equal<typeof value, Record<string, 1 | 2>>>;
  type t (line 410) | type t = Expect<Equal<typeof value, Record<string, 1 | 2> | 123>>;
  type t (line 415) | type t = Expect<
  type t (line 422) | type t = Expect<Equal<typeof value, Record<number, number>>>;
  type t (line 426) | type t = Expect<Equal<typeof value, Record<1 | 2 | 3, number>>>;
  type t (line 431) | type t = Expect<Equal<typeof value, number[]>>;
  type t (line 436) | type t = Expect<Equal<typeof value, number[]>>;
  type t (line 441) | type t = Expect<
  type t (line 450) | type t = Expect<Equal<typeof value, number[][]>>;
  type t (line 456) | type t = Expect<
  type t (line 463) | type t = Expect<Equal<typeof value, Record<string, number>[]>>;
  type t (line 468) | type t = Expect<Equal<typeof value, Record<string, number[]>>>;
  type t (line 473) | type t = Expect<
  type Input (line 527) | type Input =
  type ComplexInput (line 564) | type ComplexInput =

FILE: tests/select.test.ts
  type t (line 14) | type t = Expect<Equal<typeof y, number>>;
  type t (line 25) | type t = Expect<Equal<typeof xs, [string]>>;
  type t2 (line 26) | type t2 = Expect<Equal<typeof first, string>>;
  type t (line 30) | type t = Expect<Equal<typeof xs, string[]>>;
  type t2 (line 31) | type t2 = Expect<Equal<typeof texts, string[]>>;
  type t (line 40) | type t = Expect<Equal<typeof xs, { text: string }[]>>;
  type t2 (line 41) | type t2 = Expect<Equal<typeof texts, string[]>>;
  type t (line 55) | type t = Expect<Equal<typeof texts, string[]>>;
  type t (line 77) | type t = Expect<Equal<typeof data, string>>;
  type t2 (line 78) | type t2 = Expect<Equal<typeof other, number>>;
  type t (line 90) | type t = Expect<Equal<typeof x, string>>;
  type t (line 114) | type t = Expect<Equal<typeof time, number | undefined>>;
  type t (line 141) | type t = Expect<Equal<typeof state, State>>;
  type t2 (line 142) | type t2 = Expect<Equal<typeof event, Event>>;
  type Input (line 166) | type Input = [{ name: string }, { post: { title: string }[] }][];
  type t (line 176) | type t = Expect<Equal<typeof x, []>>;
  type t (line 185) | type t = Expect<Equal<typeof names, string[]>>;
  type t2 (line 186) | type t2 = Expect<Equal<typeof titles, string[][]>>;
  type Input (line 202) | type Input = [{ name: string }, { post: { title: string }[] }][];
  type t (line 212) | type t = Expect<Equal<typeof x, []>>;
  type t1 (line 218) | type t1 = Expect<Equal<typeof titles, string[][]>>;
  type t (line 231) | type t = Expect<Equal<typeof x, SeveralAnonymousSelectError>>;
  type t (line 240) | type t = Expect<Equal<typeof x, MixedNamedAndAnonymousSelectError>>;
  type Input (line 247) | type Input =
  type t (line 265) | type t = Expect<Equal<typeof x, { type: 'img'; src: string }>>;
  type t (line 271) | type t = Expect<
  type t (line 281) | type t = Expect<
  type t (line 287) | type t = Expect<
  type t1 (line 330) | type t1 = Expect<
  type t2 (line 336) | type t2 = Expect<Equal<typeof content, string>>;
  type t3 (line 337) | type t3 = Expect<Equal<typeof length, number>>;
  type Input (line 351) | type Input = {
  type t (line 364) | type t = Expect<
  type t (line 381) | type t = Expect<
  type Input (line 404) | type Input =
  type t (line 426) | type t = Expect<Equal<typeof x, boolean | string[]>>;
  type t (line 440) | type t = Expect<Equal<typeof a, string[]>>;
  type t2 (line 441) | type t2 = Expect<Equal<typeof b, string[]>>;
  type t (line 452) | type t = Expect<Equal<typeof a, number[]>>;
  type t (line 462) | type t = Expect<Equal<typeof a, { prop: number }[]>>;
  type t (line 476) | type t = Expect<Equal<typeof arg, string>>;

FILE: tests/sets.test.ts
  type t (line 9) | type t = Expect<Equal<typeof x, Set<'gab'>>>;
  type t (line 13) | type t = Expect<Equal<typeof x, Set<'yo'>>>;
  type t (line 17) | type t = Expect<Equal<typeof x, Set<'gab' | 'yo'>>>;
  type t (line 21) | type t = Expect<Equal<typeof x, Set<string | number>>>;
  type t (line 40) | type t = Expect<Equal<typeof res, boolean>>;

FILE: tests/strings.test.ts
  type t (line 9) | type t = Expect<Equal<typeof value, string>>;
  type t (line 13) | type t = Expect<Equal<typeof value, string | number>>;
  type t (line 26) | type t = Expect<Equal<typeof value, `hello ${string}`>>;
  type t (line 30) | type t = Expect<Equal<typeof value, string | number>>;
  type FileFrom2022 (line 38) | type FileFrom2022 = `2022-${number}-${number}`;
  type FileFrom2023 (line 39) | type FileFrom2023 = `2023-${number}-${number}`;
  type t (line 45) | type t = Expect<Equal<typeof x, FileFrom2022>>;
  type t (line 49) | type t = Expect<Equal<typeof x, FileFrom2023>>;
  type Input (line 59) | type Input = { value: FileFrom2022 | FileFrom2023 };
  type t (line 65) | type t = Expect<Equal<typeof a, { value: FileFrom2022 }>>;
  type t (line 69) | type t = Expect<Equal<typeof b, { value: FileFrom2023 }>>;
  type t (line 82) | type t = Expect<Equal<typeof value, `${string}!!`>>;
  type t (line 86) | type t = Expect<Equal<typeof value, string | number>>;
  type t (line 98) | type t = Expect<Equal<typeof value, string>>;
  type t (line 102) | type t = Expect<Equal<typeof value, string | number>>;
  type t (line 115) | type t = Expect<Equal<typeof value, string>>;
  type t (line 119) | type t = Expect<Equal<typeof value, string | number>>;
  type t (line 131) | type t = Expect<Equal<typeof value, string>>;
  type t (line 142) | type t = Expect<Equal<typeof value, string>>;
  type t (line 146) | type t = Expect<Equal<typeof value, string | number>>;
  type t (line 159) | type t = Expect<Equal<typeof value, string>>;
  type t (line 163) | type t = Expect<Equal<typeof value, string | number>>;
  type t (line 175) | type t = Expect<Equal<typeof value, string>>;
  type t (line 179) | type t = Expect<Equal<typeof value, string | number>>;

FILE: tests/tuples.test.ts
  type Input (line 22) | type Input =
  type t (line 30) | type t = Expect<Equal<typeof value, ['+', number, number]>>;
  type t (line 35) | type t = Expect<Equal<typeof value, ['*', number, number]>>;
  type t (line 40) | type t = Expect<Equal<typeof value, ['-', number]>>;
  type t (line 49) | type t = Expect<Equal<typeof value, ['+', number, number]>>;
  type t (line 54) | type t = Expect<Equal<typeof value, ['*', number, number]>>;
  type t (line 59) | type t = Expect<Equal<typeof value, ['-', number]>>;
  type t (line 82) | type t = Expect<Equal<typeof x, ['hello', 20]>>;
  type t (line 86) | type t = Expect<Equal<typeof x, ['hello', number]>>;
  type t (line 90) | type t = Expect<Equal<typeof x, [string, 20]>>;
  type t (line 94) | type t = Expect<Equal<typeof x, [string, number]>>;
  type t (line 111) | type t = Expect<Equal<typeof x, [State, { type: 'fetch' }]>>;
  type t (line 119) | type t = Expect<
  type t (line 136) | type t = Expect<
  type t (line 150) | type t = Expect<
  type State (line 176) | type State = { type: 'a' } | { type: 'b' };
  type Event (line 177) | type Event = { type: 'c' } | { type: 'd' };
  type State (line 189) | type State = {};
  type Msg (line 190) | type Msg = [type: 'Login'] | [type: 'UrlChange', url: string];
  function update (line 192) | function update(state: State, msg: Msg) {

FILE: tests/type-error.test.ts
  type Country (line 5) | type Country = 'France' | 'Germany' | 'Spain' | 'USA';
  type t (line 39) | type t = Expect<Equal<typeof x, 'France' | 'USA'>>;
  type t (line 126) | type t = Expect<Equal<typeof x, typeof input>>;

FILE: tests/type-is-matching.test.ts
  type cases (line 8) | type cases = [
  type res1 (line 27) | type res1 = IsMatching<3, number>;
  type test1 (line 28) | type test1 = Expect<Equal<res1, true>>;
  type res2 (line 30) | type res2 = IsMatching<number, 3>;
  type test2 (line 31) | type test2 = Expect<Equal<res2, true>>;
  type res3 (line 33) | type res3 = IsMatching<'hello', string>;
  type test3 (line 34) | type test3 = Expect<Equal<res3, true>>;
  type res4 (line 36) | type res4 = IsMatching<string, 'hello'>;
  type test4 (line 37) | type test4 = Expect<Equal<res4, true>>;
  type res1 (line 41) | type res1 = IsMatching<3, string>;
  type test1 (line 42) | type test1 = Expect<Equal<res1, false>>;
  type res3 (line 44) | type res3 = IsMatching<'hello', number>;
  type test3 (line 45) | type test3 = Expect<Equal<res3, false>>;
  type res1 (line 49) | type res1 = IsMatching<string | number, string>;
  type test1 (line 50) | type test1 = Expect<Equal<res1, true>>;
  type res2 (line 52) | type res2 = IsMatching<string | number, boolean>;
  type test2 (line 53) | type test2 = Expect<Equal<res2, false>>;
  type res3 (line 55) | type res3 = IsMatching<string | number, unknown>;
  type test3 (line 56) | type test3 = Expect<Equal<res3, true>>;
  type res4 (line 59) | type res4 = IsMatching<string, number | string>;
  type test4 (line 60) | type test4 = Expect<Equal<res4, true>>;
  type cases (line 65) | type cases = [
  type State (line 212) | type State = {};
  type Msg (line 213) | type Msg = [type: 'Login'] | [type: 'UrlChange', url: string];
  type res1 (line 215) | type res1 = IsMatching<[State, Msg], [unknown, ['Login', unknown]]>;
  type test1 (line 216) | type test1 = Expect<Equal<res1, false>>;
  type res2 (line 218) | type res2 = IsMatching<['a'], []>;
  type test2 (line 219) | type test2 = Expect<Equal<res2, false>>;
  type cases (line 221) | type cases = [
  type cases (line 250) | type cases = [
  type res1 (line 260) | type res1 = IsMatching<('a' | 'b')[], [unknown, ...unknown[]]>;
  type test1 (line 261) | type test1 = Expect<Equal<res1, true>>;
  type res2 (line 263) | type res2 = IsMatching<[number], [unknown, ...unknown[]]>;
  type test2 (line 264) | type test2 = Expect<Equal<res2, true>>;
  type res3 (line 266) | type res3 = IsMatching<[number, number], [unknown, ...unknown[]]>;
  type test3 (line 267) | type test3 = Expect<Equal<res3, true>>;
  type res4 (line 269) | type res4 = IsMatching<[], [unknown, ...unknown[]]>;
  type test4 (line 270) | type test4 = Expect<Equal<res4, false>>;
  type res5 (line 272) | type res5 = IsMatching<[], [...unknown[], unknown]>;
  type test5 (line 273) | type test5 = Expect<Equal<res5, false>>;
  type res6 (line 275) | type res6 = IsMatching<[1, 2], [...unknown[], unknown]>;
  type test6 (line 276) | type test6 = Expect<Equal<res6, true>>;
  type res7 (line 278) | type res7 = IsMatching<[1, 2], [1, ...unknown[], 2]>;
  type test7 (line 279) | type test7 = Expect<Equal<res7, true>>;
  type res8 (line 281) | type res8 = IsMatching<[1, 3, 2], [1, ...unknown[], 2]>;
  type test8 (line 282) | type test8 = Expect<Equal<res8, true>>;
  type res9 (line 284) | type res9 = IsMatching<[1, 3, 2], [1, ...string[], 2]>;
  type test9 (line 285) | type test9 = Expect<Equal<res9, false>>;
  type res10 (line 287) | type res10 = IsMatching<[1, 3, 2], [1, ...number[], 2]>;
  type test10 (line 288) | type test10 = Expect<Equal<res10, true>>;
  type cases (line 292) | type cases = [
  type cases (line 306) | type cases = [
  type cases (line 341) | type cases = [

FILE: tests/types-catalog/definition.ts
  type RequestStyle (line 1) | interface RequestStyle {
  type AxisBound (line 5) | type AxisBound = string | number;
  type Aggregator (line 6) | type Aggregator = 'sum' | 'avg';
  type Axis (line 8) | interface Axis {
  type DistributionXAxis (line 17) | interface DistributionXAxis {
  type DistributionYAxis (line 24) | interface DistributionYAxis {
  type Marker (line 33) | interface Marker {
  type Event (line 49) | interface Event {
  type Markers (line 54) | type Markers = Marker[];
  type ConditionalFormat (line 56) | interface ConditionalFormat {
  type ContextMenuLink (line 67) | interface ContextMenuLink {
  type UserDefinedLink (line 72) | interface UserDefinedLink {
  type CustomLink (line 77) | type CustomLink = ContextMenuLink | UserDefinedLink;
  type OrderDir (line 79) | type OrderDir = 'a' | 'b';
  type EventCompute (line 81) | type EventCompute = {
  type GroupBy (line 87) | interface GroupBy {
  type EventQuery (line 98) | type EventQuery = {
  type MetricQuery (line 108) | type MetricQuery = string;
  type ProcessQuery (line 110) | type ProcessQuery = {
  type QueryTableColumnRequest (line 119) | interface QueryTableColumnRequest {
  type ApmStatsQuery (line 125) | interface ApmStatsQuery {
  type MetricRequest (line 133) | interface MetricRequest {
  type LogRequest (line 138) | interface LogRequest {
  type ApmRequest (line 141) | interface ApmRequest {
  type ApmStatsRequest (line 144) | interface ApmStatsRequest {
  type RumRequest (line 147) | interface RumRequest {
  type EventRequest (line 150) | interface EventRequest {
  type ProcessRequest (line 153) | interface ProcessRequest {
  type ComplianceFindingsRequest (line 157) | interface ComplianceFindingsRequest {
  type IssuesRequest (line 161) | interface IssuesRequest {
  type AuditRequest (line 164) | interface AuditRequest {
  type FormulaEventsDataSource (line 168) | type FormulaEventsDataSource =
  type FormulaMetricsQuery (line 185) | type FormulaMetricsQuery = {
  type EventsCompute (line 192) | type EventsCompute = {
  type EventsAggregator (line 198) | type EventsAggregator =
  type EventsGroupBy (line 212) | type EventsGroupBy = {
  type FormulaEventsQuery (line 223) | type FormulaEventsQuery = {
  type FormulaProcessQuery (line 234) | type FormulaProcessQuery = {
  type FormulaApmDependencyStatsQuery (line 247) | interface FormulaApmDependencyStatsQuery {
  type FormulaApmResourceStatsQuery (line 259) | interface FormulaApmResourceStatsQuery {
  type FormulaApmStatsQuery (line 271) | type FormulaApmStatsQuery =
  type FormulaIncidentsQuery (line 275) | type FormulaIncidentsQuery = {
  type FormulaQuery (line 286) | type FormulaQuery =
  type FormulaQueries (line 293) | type FormulaQueries = FormulaQuery[];
  type Formula (line 295) | type Formula = {
  type TimeseriesFormulaRequest (line 304) | interface TimeseriesFormulaRequest extends TimeseriesRequest {
  type ScalarFormulaRequest (line 310) | type ScalarFormulaRequest = {
  type SQLTimeseriesRequest (line 316) | type SQLTimeseriesRequest = {
  type SQLTableRequest (line 322) | type SQLTableRequest = {
  type EventPlatformRequest (line 328) | type EventPlatformRequest =
  type TimeseriesDataSourceRequest (line 337) | type TimeseriesDataSourceRequest =
  type TimeseriesRequestStyle (line 345) | interface TimeseriesRequestStyle {
  type Metadata (line 349) | interface Metadata {
  type DisplayType (line 353) | type DisplayType = 'line' | 'bar' | 'area';
  type TimeseriesRequest (line 355) | interface TimeseriesRequest {
  type TimeseriesDefinitionRequest (line 362) | type TimeseriesDefinitionRequest = TimeseriesDataSourceRequest &
  type TimeseriesDefinition (line 365) | interface TimeseriesDefinition {
  type TableFormula (line 375) | type TableFormula = Formula & {
  type TableFormulaRequest (line 379) | type TableFormulaRequest = {
  type QueryTableDataSourceRequest (line 385) | type QueryTableDataSourceRequest =
  type QueryTableRequest (line 392) | interface QueryTableRequest {
  type QueryTableDefinitionRequest (line 400) | type QueryTableDefinitionRequest = QueryTableDataSourceRequest &
  type HasSearchBar (line 403) | type HasSearchBar = 'always' | 'never' | 'auto';
  type QueryTableDefinition (line 405) | interface QueryTableDefinition {
  type HeatmapRequest (line 412) | interface HeatmapRequest {
  type HeatmapDefinitionRequest (line 416) | interface HeatmapDefinitionRequest extends MetricRequest, HeatmapRequest {}
  type HeatmapDefinition (line 418) | interface HeatmapDefinition {
  type ServiceMapDefinition (line 426) | interface ServiceMapDefinition {
  type TreemapProcessMemoryRequest (line 432) | type TreemapProcessMemoryRequest = { q: string };
  type TreemapDataSourceRequest (line 434) | type TreemapDataSourceRequest =
  type TreemapSizeBy (line 438) | type TreemapSizeBy = 'pct_cpu' | 'pct_mem';
  type TreemapColorBy (line 440) | type TreemapColorBy = 'user';
  type TreemapGroupBy (line 442) | type TreemapGroupBy = 'family' | 'process' | 'user';
  type TreemapDefinition (line 444) | interface TreemapDefinition {
  type TopListRequest (line 452) | interface TopListRequest {
  type TopListDataSourceRequest (line 456) | type TopListDataSourceRequest =
  type TopListDefinitionRequest (line 463) | type TopListDefinitionRequest = TopListDataSourceRequest & TopListRequest;
  type TopListDefinition (line 465) | interface TopListDefinition {
  type DistributionDataSourceRequest (line 471) | type DistributionDataSourceRequest =
  type DistributionRequest (line 477) | interface DistributionRequest {
  type DistributionDefinitionRequest (line 481) | type DistributionDefinitionRequest = DistributionDataSourceRequest &
  type DistributionDefinition (line 484) | interface DistributionDefinition {
  type ScatterPlotDimension (line 493) | type ScatterPlotDimension = 'x' | 'y' | 'radius' | 'color';
  type ScatterplotFormula (line 495) | type ScatterplotFormula = Formula & {
  type ScatterplotScalarFormulaRequest (line 499) | interface ScatterplotScalarFormulaRequest extends ScalarFormulaRequest {
  type ScatterplotDataSourceRequest (line 503) | type ScatterplotDataSourceRequest =
  type ScatterplotRequest (line 508) | interface ScatterplotRequest {
  type ScatterplotDefinitionRequest (line 512) | type ScatterplotDefinitionRequest = ScatterplotDataSourceRequest &
  type ScatterplotDefinition (line 515) | interface ScatterplotDefinition {
  type GeomapStyle (line 524) | interface GeomapStyle {
  type GeomapView (line 528) | interface GeomapView {
  type GeomapDefinitionRequest (line 532) | type GeomapDefinitionRequest =
  type GeomapDefinition (line 538) | interface GeomapDefinition {
  type PlotPaletteName (line 546) | type PlotPaletteName = 'red' | 'blue' | 'orange';
  type SunburstRequest (line 548) | type SunburstRequest = {
  type SunburstDefinitionRequest (line 554) | interface SunburstDefinitionRequest
  type SunburstKnownLegend (line 558) | type SunburstKnownLegend =
  type SunburstLegend (line 563) | type SunburstLegend =
  type SunburstDefinition (line 567) | type SunburstDefinition = {
  type WildcardDefinitionRequest (line 574) | type WildcardDefinitionRequest = SQLTableRequest | ScalarFormulaRequest;
  type WildcardDefinition (line 576) | type WildcardDefinition = {
  type Definition (line 585) | type Definition =

FILE: tests/types-catalog/utils.ts
  type Option (line 1) | type Option<a> = { kind: 'none' } | { kind: 'some'; value: a };
  type Blog (line 9) | type Blog = {
  type State (line 14) | type State =
  type Event (line 20) | type Event =
  type BigUnion (line 26) | type BigUnion =
  type AsyncResultStatus (line 54) | type AsyncResultStatus = 'idle' | 'loading' | 'error' | 'success';
  type BaseAsyncResult (line 56) | interface BaseAsyncResult<TData, TError = Error> {
  type AsyncResultIdleOrLoading (line 62) | interface AsyncResultIdleOrLoading<TData, TError = Error>
  type AsyncResultSuccess (line 67) | interface AsyncResultSuccess<TData, TError = Error>
  type AsyncResultError (line 73) | interface AsyncResultError<TData, TError = Error>
  type AsyncResult (line 78) | type AsyncResult<TData, TError = Error> =

FILE: tests/types.test.ts
  type Input (line 6) | type Input = [State, Event];
  type t (line 26) | type t = Expect<Equal<typeof x, Input>>;
  type t (line 32) | type t = Expect<Equal<typeof state, State>>;
  type t (line 36) | type t = Expect<Equal<typeof event, Event>>;
  type t (line 50) | type t = Expect<Equal<typeof d, string>>;
  type t (line 70) | type t = Expect<Equal<typeof x, string>>;
  type t (line 78) | type t = Expect<Equal<typeof x, string>>;
  type t (line 87) | type t = Expect<Equal<typeof x, string>>;
  type t (line 93) | type t = Expect<Equal<typeof y, number>>;
  type t (line 100) | type t = Expect<Equal<typeof x, string | number>>;
  type Input (line 106) | type Input = { type: string; hello?: { yo: number } } | string;
  type t (line 109) | type t = Expect<Equal<typeof x, string>>;
  type t (line 114) | type t = Expect<Equal<typeof x, string>>;
  type t (line 121) | type t = Expect<Equal<typeof x, Input>>;
  type t (line 128) | type t = Expect<Equal<typeof x, Input>>;
  type t (line 132) | type t = Expect<Equal<typeof x, Input>>;
  type t (line 137) | type t = Expect<Equal<typeof x, Input>>;
  type t (line 141) | type t = Expect<
  type t (line 156) | type t = Expect<Equal<typeof x, Input>>;
  type t (line 160) | type t = Expect<
  type t (line 174) | type t = Expect<
  type t (line 180) | type t = Expect<
  type t (line 188) | type t = Expect<
  type t (line 202) | type t = Expect<Equal<typeof x, Input>>;
  type t (line 208) | type t = Expect<Equal<typeof x, Input>>;
  type t (line 215) | type t = Expect<Equal<typeof x, string>>;
  type t (line 220) | type t = Expect<Equal<typeof x, string>>;
  type t (line 224) | type t = Expect<Equal<typeof x, Input>>;
  type Input (line 230) | type Input =
  type t (line 240) | type t = Expect<Equal<typeof x, string>>;
  type t (line 244) | type t = Expect<Equal<typeof x, number>>;
  type t (line 248) | type t = Expect<Equal<typeof x, boolean>>;
  type t (line 252) | type t = Expect<Equal<typeof x, { type: string }>>;
  type t (line 256) | type t = Expect<Equal<typeof x, { type: string | number }>>;
  type t (line 260) | type t = Expect<Equal<typeof x, [string]>>;
  type t (line 264) | type t = Expect<Equal<typeof x, [number, number]>>;
  type Input (line 333) | type Input = { type: 'a'; data: string } | { type: 'b'; data: number };
  type Input (line 350) | type Input = { type: 'a'; data: string } | { type: 'b'; data: number };
  type test (line 377) | type test = Expect<Equal<typeof x, 'a' | 'b'>>;

FILE: tests/unions.test.ts
  type t (line 14) | type t = Expect<Equal<typeof o, { kind: 'some'; value: string }>>;
  type t (line 20) | type t = Expect<Equal<typeof res, string>>;
  type Post (line 26) | type Post = {
  type Video (line 31) | type Video = { type: 'video'; id: number; content: { src: string } };
  type Image (line 32) | type Image = { type: 'image'; id: number; content: { src: number } };
  type Input (line 34) | type Input = Post | Video | Image;
  type t (line 42) | type t = Expect<
  type t (line 57) | type t = Expect<Equal<typeof x, Post>>;
  type t (line 61) | type t = Expect<Equal<typeof x, Video>>;
  type t (line 65) | type t = Expect<Equal<typeof x, Image>>;
  type Text (line 74) | type Text = { type: 'text'; content: string };
  type Img (line 75) | type Img = { type: 'img'; src: string };
  type Video (line 76) | type Video = { type: 'video'; src: string };
  type Story (line 77) | type Story = {
  type Data (line 84) | type Data = Text | Img | Video | Story;
  type Ok (line 86) | type Ok<T> = { type: 'ok'; data: T };
  type ResError (line 87) | type ResError<T> = { type: 'error'; error: T };
  type Result (line 89) | type Result<TError, TOk> = Ok<TOk> | ResError<TError>;
  type t (line 98) | type t = Expect<Equal<typeof res, Ok<Text>>>;
  type t (line 102) | type t = Expect<Equal<typeof res, Ok<Img>>>;
  type t (line 106) | type t = Expect<
  type t (line 124) | type t = Expect<Equal<typeof res, ResError<Error>>>;
  type ServerError (line 133) | type ServerError = Error & {
  type ServerParseError (line 139) | type ServerParseError = Error & {
  type Input (line 145) | type Input = Error | ServerError | ServerParseError | undefined;

FILE: tests/variadic-tuples.test.ts
  type t (line 190) | type t = Expect<Equal<typeof xs, [unknown, ...unknown[]]>>;
  type t (line 199) | type t = Expect<Equal<typeof xs, [...unknown[], number]>>;
  type t (line 208) | type t = Expect<Equal<typeof xs, [42, ...number[]]>>;
  type t (line 217) | type t = Expect<Equal<typeof xs, [42, ...number[], '!']>>;
  type t (line 226) | type t = Expect<Equal<typeof xs, [1, 2, ...number[]]>>;
  type t (line 235) | type t = Expect<Equal<typeof xs, [...string[], 'a', 'b']>>;
  type t (line 248) | type t = Expect<
  type t (line 257) | type t = Expect<Equal<typeof xs, [...(string | number)[], 7]>>;
  type t (line 264) | type t = Expect<Equal<typeof xs, [42, ...number[]]>>;
  type t (line 271) | type t = Expect<Equal<typeof xs, [42, ...number[], 7]>>;
  type t (line 280) | type t = Expect<
  type t (line 290) | type t = Expect<
  type t (line 323) | type t = Expect<
  type t (line 358) | type t = Expect<Equal<typeof xs, [1, 2, ...number[]]>>;
  type t (line 365) | type t = Expect<Equal<typeof xs, [...string[], 'a', 'b']>>;
  type t (line 376) | type t = Expect<Equal<typeof xs, string | number>>;
  type t (line 383) | type t = Expect<Equal<typeof xs, (string | number)[]>>;
  type t (line 390) | type t = Expect<Equal<typeof xs, number[]>>;
  type t (line 399) | type t = Expect<Equal<typeof xs, { tail: number[]; head: 42 }>>;
  type t (line 407) | type t = Expect<Equal<typeof xs, number[]>>;
  type t (line 419) | type t = Expect<Equal<typeof xs, { c: number[]; a: 1; b: 2 }>>;
  type t (line 425) | type t = Expect<Equal<typeof xs, 2>>;
  type t (line 432) | type t = Expect<Equal<typeof xs, string[]>>;
  type t (line 440) | type t = Expect<Equal<typeof xs, { inits: string[]; last: 'a' }>>;
  type t (line 446) | type t = Expect<Equal<typeof xs, string | number>>;
  type t (line 453) | type t = Expect<Equal<typeof xs, string[]>>;
  type t (line 460) | type t = Expect<Equal<typeof xs, 2>>;
  type t (line 473) | type t = Expect<Equal<typeof xs, { a: string[]; b: 2; c: 'b' }>>;
  type t (line 481) | type t = Expect<Equal<typeof xs, number[]>>;
  type t (line 494) | type t = Expect<Equal<typeof xs, { b: number[]; a: 42; c: '!' }>>;
  type t (line 525) | type t = Expect<Equal<typeof res, 'branch 1' | 'branch 2'>>;
  type t (line 562) | type t = Expect<Equal<typeof res, 'branch 1' | 'branch 2' | 'branch 3'>>;
  type t (line 573) | type t = Expect<Equal<typeof rest, number[]>>;
  type t (line 577) | type t = Expect<Equal<typeof rest, number[]>>;
  type t (line 581) | type t = Expect<Equal<typeof rest, (number | string)[]>>;
  type t (line 596) | type t = Expect<Equal<typeof rest, number[]>>;
  type t (line 600) | type t = Expect<Equal<typeof rest, number[]>>;
  type t (line 604) | type t = Expect<Equal<typeof rest, number[]>>;
  type t (line 608) | type t = Expect<Equal<typeof rest, number[]>>;
  type t (line 612) | type t = Expect<Equal<typeof rest, (number | number[] | string)[]>>;

FILE: tests/when.test.ts
  type t (line 34) | type t = Expect<Equal<typeof x, 13>>;
  type t (line 40) | type t = Expect<Equal<typeof res, boolean>>;
  type t (line 65) | type t = Expect<Equal<typeof res, Option<string>>>;
  type t (line 77) | type t = Expect<Equal<typeof x, number>>;
  type t (line 119) | type t = Expect<
  type t (line 129) | type t = Expect<Equal<typeof x, { data: string }>>;
  type t (line 138) | type t = Expect<Equal<typeof x, { data: string }>>;
  type t (line 163) | type t = Expect<Equal<typeof x, 2>>;
  type t (line 181) | type t = Expect<Equal<typeof x, number>>;
  type Option (line 194) | type Option<T> = { type: 'some'; value: T } | { type: 'none' };
  type t (line 218) | type t = Expect<Equal<typeof x, string>>;
  type t (line 226) | type t = Expect<
  type t (line 258) | type t = Expect<
  type t (line 279) | type t = Expect<Equal<typeof x, string[]>>;
  type Input (line 334) | type Input = string | { prop: string | number };
  type t (line 340) | type t = Expect<Equal<typeof x, { prop: string }>>;
  type Input (line 356) | type Input = { prop: string | number };
  type t (line 361) | type t = Expect<Equal<typeof x, { prop: number }>>;
  type Data (line 370) | type Data = { digit: number };
  type Input (line 372) | type Input = {
  type t (line 382) | type t = Expect<Equal<typeof data, Data | undefined>>;

FILE: tests/wildcards.test.ts
  type t (line 12) | type t = Expect<Equal<typeof x, string>>;
  type t (line 23) | type t = Expect<Equal<typeof x, number>>;
  type t (line 34) | type t = Expect<Equal<typeof x, boolean>>;
  type t (line 45) | type t = Expect<Equal<typeof x, null | undefined>>;
  type t (line 52) | type t = Expect<Equal<typeof x, null | undefined>>;
  type Input (line 63) | type Input = string | number | boolean | null | undefined;
  type t (line 66) | type t = Expect<Equal<typeof x, string | number | boolean>>;
  type t (line 73) | type t = Expect<Equal<typeof x, 0 | 1 | 2>>;
  type Input (line 84) | type Input =
  type X (line 97) | type X = InvertPattern<typeof pattern, Input>;
  type Y (line 98) | type Y = ExtractPreciseValue<Input, X>;
  type t (line 105) | type t = Expect<Equal<typeof fields, string[]>>;
  type t (line 121) | type t = Expect<Equal<typeof x, string | number>>;
  type t (line 130) | type t = Expect<Equal<typeof x, { nested: string | number }>>;
  type t (line 133) | type t = Expect<Equal<typeof x, { nested: null | undefined }>>;
  type t (line 164) | type t = Expect<Equal<typeof x, number | boolean>>;
  type t (line 175) | type t = Expect<Equal<typeof x, string | boolean>>;
  type t (line 186) | type t = Expect<Equal<typeof x, string | number>>;
  type Id (line 195) | type Id = { teamId: number } | { storeId: number };
Condensed preview — 99 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (631K chars).
[
  {
    "path": ".github/FUNDING.yml",
    "chars": 835,
    "preview": "# These are supported funding model platforms\n\ngithub: [gvergnaud] # Replace with up to 4 GitHub Sponsors-enabled userna"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "chars": 535,
    "preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Describe the b"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "chars": 604,
    "preview": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: enhancement\nassignees: ''\n\n---\n\n**Is"
  },
  {
    "path": ".gitignore",
    "chars": 99,
    "preview": ".DS_Store\nnode_modules\nnpm-debug.log\nlib\ndist\nnotes.md\n.vscode/\ntracing_output_folder/\ntrace/\n*.tgz"
  },
  {
    "path": ".prettierrc",
    "chars": 27,
    "preview": "{\n    \"singleQuote\": true\n}"
  },
  {
    "path": "LICENSE",
    "chars": 1073,
    "preview": "MIT License\n\nCopyright (c) 2021 Gabriel Vergnaud\n\nPermission is hereby granted, free of charge, to any person obtaining "
  },
  {
    "path": "README.md",
    "chars": 50555,
    "preview": "<h1 align=\"center\">TS-Pattern</h1>\n\n<p align=\"center\">\nThe exhaustive Pattern Matching library for <a href=\"https://gith"
  },
  {
    "path": "benchmarks/always-last-digit.ts",
    "chars": 2463,
    "preview": "import { add, complete, cycle, suite } from 'benny';\nimport { match } from '../src';\n\ntype Digit = 0 | 1 | 2 | 3 | 4 | 5"
  },
  {
    "path": "benchmarks/nested-objects.ts",
    "chars": 1846,
    "preview": "import { add, complete, cycle, suite } from 'benny';\nimport { P, match } from '../src';\n\nconst testExhaustive = (input: "
  },
  {
    "path": "benchmarks/package.json",
    "chars": 509,
    "preview": "{\n  \"name\": \"ts-pattern-benchmarks\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n   "
  },
  {
    "path": "benchmarks/random-digit.ts",
    "chars": 2549,
    "preview": "import { add, complete, cycle, suite } from 'benny';\nimport { match } from '../src';\n\ntype Digit = 0 | 1 | 2 | 3 | 4 | 5"
  },
  {
    "path": "docs/roadmap.md",
    "chars": 2593,
    "preview": "### Roadmap\n\n- [ ] `P.ExactPattern<Type>` to infer the exact pattern you must write to fully cover all possible properti"
  },
  {
    "path": "docs/v3-to-v4-migration-guide.md",
    "chars": 8776,
    "preview": "# TS-Pattern v3 to v4 Migration Guide\n\n## Breaking changes\n\n### Imports\n\ntype-specific wildcard patterns have moved from"
  },
  {
    "path": "docs/v4-to-v5-migration-guide.md",
    "chars": 8138,
    "preview": "# TS-Pattern v4 to v5 Migration Guide\n\nThis file contains all breaking changes and new features between the version 4 an"
  },
  {
    "path": "examples/gif-fetcher/package.json",
    "chars": 622,
    "preview": "{\n  \"name\": \"ts-pattern-v4-gif-search-demo\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"keywords\": [],\n  \"main\": \"src"
  },
  {
    "path": "examples/gif-fetcher/public/index.html",
    "chars": 255,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "examples/gif-fetcher/src/App.tsx",
    "chars": 3528,
    "preview": "import { searchGif } from './searchGif';\nimport { throttle } from 'lodash';\nimport * as React from 'react';\nimport './st"
  },
  {
    "path": "examples/gif-fetcher/src/constants.ts",
    "chars": 43,
    "preview": "export const API_KEY = 'xxxxxxxxxxxxxxxx';\n"
  },
  {
    "path": "examples/gif-fetcher/src/index.tsx",
    "chars": 178,
    "preview": "import * as React from 'react';\nimport { render } from 'react-dom';\n\nimport App from './App';\n\nconst rootElement = docum"
  },
  {
    "path": "examples/gif-fetcher/src/searchGif.ts",
    "chars": 949,
    "preview": "import { isMatching, P } from 'ts-pattern';\nimport { API_KEY } from './constants';\n\nconst delay = (ms: number) => new Pr"
  },
  {
    "path": "examples/gif-fetcher/src/styles.css",
    "chars": 419,
    "preview": "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: "
  },
  {
    "path": "examples/gif-fetcher/tsconfig.json",
    "chars": 393,
    "preview": "{\n  \"compilerOptions\": {\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true,\n    \"target\": \"es2022\",\n    \"allowJs\": t"
  },
  {
    "path": "examples/one-file-demo/one-file-demo.ts",
    "chars": 5089,
    "preview": "import { isMatching, match, P } from 'ts-pattern';\n\n/**\n * ### One file TS-Pattern demo.\n *\n * This will demonstrate:\n *"
  },
  {
    "path": "examples/one-file-demo/package.json",
    "chars": 164,
    "preview": "{\n  \"name\": \"ts-pattern-examples\",\n  \"version\": \"1.0.0\",\n  \"main\": \"one-file-demo.ts\",\n  \"author\": \"gvergnaud\",\n  \"depen"
  },
  {
    "path": "examples/one-file-demo/tsconfig.json",
    "chars": 156,
    "preview": "{\n  \"compilerOptions\": {\n    \"strict\": true,\n    \"lib\": [\"ES2015\"],\n    \"target\": \"ES2015\",\n    \"moduleResolution\": \"bun"
  },
  {
    "path": "jest.config.cjs",
    "chars": 70,
    "preview": "module.exports = {\n  preset: 'ts-jest',\n  testEnvironment: 'node',\n};\n"
  },
  {
    "path": "jsr.json",
    "chars": 176,
    "preview": "{\n  \"name\": \"@gabriel/ts-pattern\",\n  \"version\": \"5.9.0\",\n  \"exports\": {\n    \".\": \"./src/index.ts\",\n    \"./types\": \"./src"
  },
  {
    "path": "package.json",
    "chars": 2344,
    "preview": "{\n  \"name\": \"ts-pattern\",\n  \"version\": \"5.9.0\",\n  \"description\": \" The exhaustive Pattern Matching library for TypeScrip"
  },
  {
    "path": "scripts/generate-cts.sh",
    "chars": 725,
    "preview": "#!/bin/bash\n\n# TypeScript projects using `moduleResolution: nodenext` expect\n# explicit extensions to be included in dec"
  },
  {
    "path": "src/errors.ts",
    "chars": 423,
    "preview": "/**\n * Error when the given input value does not match any included pattern\n * and .exhaustive() was specified\n */\nexpor"
  },
  {
    "path": "src/index.ts",
    "chars": 198,
    "preview": "import * as Pattern from './patterns';\n\nexport { match } from './match';\nexport { isMatching } from './is-matching';\nexp"
  },
  {
    "path": "src/internals/helpers.ts",
    "chars": 3944,
    "preview": "/**\n * @module\n * @private\n * @internal\n */\n\nimport * as symbols from './symbols';\nimport { SelectionType } from '../typ"
  },
  {
    "path": "src/internals/symbols.ts",
    "chars": 1082,
    "preview": "/**\n * Symbols used internally within ts-pattern to construct and discriminate\n * Guard, Not, and Select, and AnonymousS"
  },
  {
    "path": "src/is-matching.ts",
    "chars": 2168,
    "preview": "import { MatchedValue, Pattern, UnknownProperties } from './types/Pattern';\nimport * as P from './patterns';\nimport { ma"
  },
  {
    "path": "src/match.ts",
    "chars": 3808,
    "preview": "import { Pattern } from './types/Pattern';\nimport { Match } from './types/Match';\nimport * as symbols from './internals/"
  },
  {
    "path": "src/patterns.ts",
    "chars": 40110,
    "preview": "/**\n * The `P` module contains patterns for primitive types, wildcards and\n * other pattern-matching utilities.\n *\n * @m"
  },
  {
    "path": "src/types/BuildMany.ts",
    "chars": 1547,
    "preview": "import { Iterator, IsOptionalKeysOf, UpdateAt, ValueOf } from './helpers';\n\n// BuildMany :: DataStructure -> Union<[valu"
  },
  {
    "path": "src/types/DeepExclude.ts",
    "chars": 140,
    "preview": "import { DistributeMatchingUnions } from './DistributeUnions';\n\nexport type DeepExclude<a, b> = Exclude<DistributeMatchi"
  },
  {
    "path": "src/types/DistributeUnions.ts",
    "chars": 5866,
    "preview": "import { BuildMany } from './BuildMany';\nimport type {\n  IsAny,\n  Values,\n  Flatten,\n  IsUnion,\n  IsPlainObject,\n  Lengt"
  },
  {
    "path": "src/types/ExtractPreciseValue.ts",
    "chars": 4666,
    "preview": "import type { Override } from './Pattern';\nimport type {\n  BuiltInObjects,\n  Compute,\n  Contains,\n  IsPlainObject,\n  IsR"
  },
  {
    "path": "src/types/FindSelected.ts",
    "chars": 6420,
    "preview": "import type * as symbols from '../internals/symbols';\nimport type { AnyMatcher, Matcher, Pattern } from './Pattern';\nimp"
  },
  {
    "path": "src/types/InvertPattern.ts",
    "chars": 12291,
    "preview": "import { DeepExclude } from './DeepExclude';\nimport {\n  IsPlainObject,\n  Primitives,\n  IsLiteral,\n  ValueOf,\n  Compute,\n"
  },
  {
    "path": "src/types/IsMatching.ts",
    "chars": 3245,
    "preview": "import {\n  Primitives,\n  IsPlainObject,\n  IsUnion,\n  ValueOf,\n  Length,\n  IsLiteral,\n  All,\n  Equal,\n} from './helpers';"
  },
  {
    "path": "src/types/Match.ts",
    "chars": 9422,
    "preview": "import type * as symbols from '../internals/symbols';\nimport type { Pattern, MatchedValue } from './Pattern';\nimport typ"
  },
  {
    "path": "src/types/Pattern.ts",
    "chars": 22394,
    "preview": "import type * as symbols from '../internals/symbols';\nimport { MergeUnion, Primitives, WithDefault } from './helpers';\ni"
  },
  {
    "path": "src/types/helpers.ts",
    "chars": 6871,
    "preview": "export type ValueOf<a> = a extends readonly any[] ? a[number] : a[keyof a];\n\nexport type Values<a extends object> = Unio"
  },
  {
    "path": "src/types/index.ts",
    "chars": 26,
    "preview": "export * from './Pattern';"
  },
  {
    "path": "tests/bigints.test.ts",
    "chars": 3516,
    "preview": "import { P, match } from '../src';\nimport { Equal, Expect } from '../src/types/helpers';\n\ndescribe('BigInts', () => {\n  "
  },
  {
    "path": "tests/branded-nominal-types.test.ts",
    "chars": 1643,
    "preview": "import { match, P } from '../src';\n\ndescribe('Branded strings', () => {\n  type BrandedId = string & { __brand: 'brandId'"
  },
  {
    "path": "tests/build-many.test.ts",
    "chars": 720,
    "preview": "import { BuildMany } from '../src/types/BuildMany';\nimport { Equal, Expect } from '../src/types/helpers';\nimport { State"
  },
  {
    "path": "tests/chainable.test.ts",
    "chars": 8175,
    "preview": "import { P, match } from '../src';\nimport { Equal, Expect } from '../src/types/helpers';\n\ndescribe('chainable methods', "
  },
  {
    "path": "tests/deep-exclude.test.ts",
    "chars": 17432,
    "preview": "import { DeepExclude } from '../src/types/DeepExclude';\nimport {\n  DistributeMatchingUnions,\n  FindUnions,\n  FindUnionsM"
  },
  {
    "path": "tests/distribute-unions.test.ts",
    "chars": 26395,
    "preview": "import {\n  FindUnions,\n  Distribute,\n  DistributeMatchingUnions,\n  FindUnionsMany,\n} from '../src/types/DistributeUnions"
  },
  {
    "path": "tests/exhaustive-fallback.test.ts",
    "chars": 1503,
    "preview": "import { match, P } from '../src';\nimport { Equal, Expect } from '../src/types/helpers';\n\ndescribe('Exhaustive fallback "
  },
  {
    "path": "tests/exhaustive-match.test.ts",
    "chars": 31826,
    "preview": "import { NonExhaustiveError, match, P } from '../src';\nimport { Equal, Expect } from '../src/types/helpers';\nimport {\n  "
  },
  {
    "path": "tests/extract-precise-value.test.ts",
    "chars": 14787,
    "preview": "import { ExtractPreciseValue } from '../src/types/ExtractPreciseValue';\nimport { InvertPattern } from '../src/types/Inve"
  },
  {
    "path": "tests/find-selected.test.ts",
    "chars": 13946,
    "preview": "import * as symbols from '../src/internals/symbols';\nimport {\n  FindSelected,\n  MixedNamedAndAnonymousSelectError,\n  Sev"
  },
  {
    "path": "tests/generics.test.ts",
    "chars": 4664,
    "preview": "import { match, P } from '../src';\nimport { Equal, Expect } from '../src/types/helpers';\nimport {\n  AsyncResult,\n  Async"
  },
  {
    "path": "tests/helpers.test.ts",
    "chars": 4873,
    "preview": "import {\n  Drop,\n  Equal,\n  Expect,\n  Iterator,\n  LeastUpperBound,\n  Take,\n  IntersectObjects,\n  UpdateAt,\n  IsReadonlyA"
  },
  {
    "path": "tests/infer.test.ts",
    "chars": 1284,
    "preview": "import { P } from '../src';\nimport { Equal, Expect } from '../src/types/helpers';\n\ndescribe('P.infer', () => {\n  describ"
  },
  {
    "path": "tests/instance-of.test.ts",
    "chars": 2286,
    "preview": "import { Expect, Equal } from '../src/types/helpers';\nimport { match, P } from '../src';\n\nclass A {\n  a = 'a';\n}\nclass B"
  },
  {
    "path": "tests/intersection-and-union.test.ts",
    "chars": 20879,
    "preview": "import { match, P } from '../src';\nimport { Equal, Expect } from '../src/types/helpers';\n\ndescribe('and, and or patterns"
  },
  {
    "path": "tests/invert-pattern.test.ts",
    "chars": 12781,
    "preview": "import { Equal, Expect } from '../src/types/helpers';\nimport {\n  InvertPattern,\n  InvertPatternForExclude,\n} from '../sr"
  },
  {
    "path": "tests/is-matching.test.ts",
    "chars": 4964,
    "preview": "import { isMatching, P } from '../src';\nimport { Equal, Expect } from '../src/types/helpers';\n\ndescribe('isMatching', ()"
  },
  {
    "path": "tests/large-exhaustive.test.ts",
    "chars": 15873,
    "preview": "import { match, P } from '../src';\nimport { Compute, Equal, Expect, Not } from '../src/types/helpers';\n\ndescribe('large "
  },
  {
    "path": "tests/lists.test.ts",
    "chars": 2249,
    "preview": "import { match, P } from '../src';\nimport { Expect, Equal } from '../src/types/helpers';\nimport { Option, Blog } from '."
  },
  {
    "path": "tests/maps.test.ts",
    "chars": 1117,
    "preview": "import { Expect, Equal } from '../src/types/helpers';\nimport { match, P } from '../src';\n\ndescribe('Map', () => {\n  it('"
  },
  {
    "path": "tests/matcher-protocol.test.ts",
    "chars": 3297,
    "preview": "import { isMatching, match, P } from '../src';\nimport { Equal, Expect } from '../src/types/helpers';\n\ndescribe('matcher "
  },
  {
    "path": "tests/multiple-patterns.test.ts",
    "chars": 7901,
    "preview": "import { match, P } from '../src';\nimport { Option } from './types-catalog/utils';\nimport { Expect, Equal } from '../src"
  },
  {
    "path": "tests/narrow.test.ts",
    "chars": 1102,
    "preview": "import { P, match } from '../src';\nimport { Equal, Expect } from '../src/types/helpers';\n\ndescribe('P.narrow', () => {\n "
  },
  {
    "path": "tests/nesting.test.ts",
    "chars": 4902,
    "preview": "import { Expect, Equal } from '../src/types/helpers';\nimport { match, P } from '../src';\n\ndescribe('Nesting', () => {\n  "
  },
  {
    "path": "tests/not.test.ts",
    "chars": 8264,
    "preview": "import { Expect, Equal } from '../src/types/helpers';\nimport { match, P } from '../src';\nimport { Option } from './types"
  },
  {
    "path": "tests/numbers.test.ts",
    "chars": 6288,
    "preview": "import { Expect, Equal } from '../src/types/helpers';\nimport { match, P } from '../src';\n\ndescribe('Numbers', () => {\n  "
  },
  {
    "path": "tests/objects.test.ts",
    "chars": 3678,
    "preview": "import { isMatching, match, P } from '../src';\nimport { Equal, Expect } from '../src/types/helpers';\n\ndescribe('Objects'"
  },
  {
    "path": "tests/optional-props.test.ts",
    "chars": 3022,
    "preview": "import { Expect, Equal } from '../src/types/helpers';\nimport { match, P } from '../src';\n\ndescribe('optional properties'"
  },
  {
    "path": "tests/optional.test.ts",
    "chars": 5695,
    "preview": "import { match, P } from '../src';\nimport { Equal, Expect } from '../src/types/helpers';\n\ndescribe('optional', () => {\n "
  },
  {
    "path": "tests/otherwise.test.ts",
    "chars": 248,
    "preview": "import { match } from '../src';\n\ndescribe('otherwise', () => {\n  it('should pass matched value to otherwise', () => {\n  "
  },
  {
    "path": "tests/output-type.test.ts",
    "chars": 5257,
    "preview": "import { match, P } from '../src';\nimport { Equal, Expect } from '../src/types/helpers';\nimport { State } from './types-"
  },
  {
    "path": "tests/pattern.test.ts",
    "chars": 2957,
    "preview": "import { P } from '../src';\nimport { Equal, Expect } from '../src/types/helpers';\nimport { Matcher } from '../src/types/"
  },
  {
    "path": "tests/primitive-values.test.ts",
    "chars": 2533,
    "preview": "import { match, P } from '../src';\nimport { Equal, Expect } from '../src/types/helpers';\n\ndescribe('Primitive values', ("
  },
  {
    "path": "tests/readonly.test.ts",
    "chars": 2726,
    "preview": "import { P, match } from '../src';\nimport { Equal, Expect } from '../src/types/helpers';\n\ndescribe('readonly', () => {\n "
  },
  {
    "path": "tests/real-world.test.ts",
    "chars": 5260,
    "preview": "import { match, P } from '../src';\nimport { Equal, Expect } from '../src/types/helpers';\nimport { Definition } from './t"
  },
  {
    "path": "tests/record.test.ts",
    "chars": 18355,
    "preview": "import { Expect, Equal } from '../src/types/helpers';\nimport { match, P } from '../src';\n\ndescribe('P.record', () => {\n "
  },
  {
    "path": "tests/return-type.test.ts",
    "chars": 1459,
    "preview": "import { P, match } from '../src';\n\ndescribe('returnType', () => {\n  it('should only be allowed directly after match(..."
  },
  {
    "path": "tests/select.test.ts",
    "chars": 14887,
    "preview": "import { Expect, Equal } from '../src/types/helpers';\nimport { match, P } from '../src';\nimport { State, Event } from '."
  },
  {
    "path": "tests/sets.test.ts",
    "chars": 1513,
    "preview": "import { Expect, Equal } from '../src/types/helpers';\nimport { match, P } from '../src';\n\ndescribe('Set', () => {\n  it('"
  },
  {
    "path": "tests/strings.test.ts",
    "chars": 5910,
    "preview": "import { P, match } from '../src';\nimport { Equal, Expect } from '../src/types/helpers';\n\ndescribe('Strings', () => {\n  "
  },
  {
    "path": "tests/tsconfig.json",
    "chars": 302,
    "preview": "{\n  \"compilerOptions\": {\n    \"strict\": true,\n    \"downlevelIteration\": true,\n    \"noEmit\": true,\n    \"target\": \"ESNext\","
  },
  {
    "path": "tests/tuples.test.ts",
    "chars": 5906,
    "preview": "import { Expect, Equal } from '../src/types/helpers';\nimport { match, P } from '../src';\nimport { State, Event } from '."
  },
  {
    "path": "tests/type-error.test.ts",
    "chars": 4460,
    "preview": "import { match, P } from '../src';\nimport { Equal, Expect } from '../src/types/helpers';\nimport { Option } from './types"
  },
  {
    "path": "tests/type-is-matching.test.ts",
    "chars": 10977,
    "preview": "import { Equal, Expect, IsPlainObject, Primitives } from '../src/types/helpers';\nimport { IsMatching } from '../src/type"
  },
  {
    "path": "tests/types-catalog/definition.ts",
    "chars": 11557,
    "preview": "interface RequestStyle {\n  palette?: string;\n}\n\ntype AxisBound = string | number;\ntype Aggregator = 'sum' | 'avg';\n\ninte"
  },
  {
    "path": "tests/types-catalog/utils.ts",
    "chars": 1587,
    "preview": "export type Option<a> = { kind: 'none' } | { kind: 'some'; value: a };\n\nexport const none: Option<never> = { kind: 'none"
  },
  {
    "path": "tests/types.test.ts",
    "chars": 11634,
    "preview": "import { Expect, Equal } from '../src/types/helpers';\nimport { match, P } from '../src';\nimport { State, Event } from '."
  },
  {
    "path": "tests/unions.test.ts",
    "chars": 4451,
    "preview": "import { Expect, Equal } from '../src/types/helpers';\nimport { match, P } from '../src';\nimport { Option } from './types"
  },
  {
    "path": "tests/variadic-tuples.test.ts",
    "chars": 18821,
    "preview": "import { match, P } from '../src';\nimport { Equal, Expect } from '../src/types/helpers';\n\ndescribe('variadic tuples ([a,"
  },
  {
    "path": "tests/when.test.ts",
    "chars": 11209,
    "preview": "import { Expect, Equal } from '../src/types/helpers';\nimport { match, P, Pattern } from '../src';\nimport { Option, State"
  },
  {
    "path": "tests/wildcards.test.ts",
    "chars": 6763,
    "preview": "import { Expect, Equal } from '../src/types/helpers';\nimport { match, P } from '../src';\nimport { Blog } from './types-c"
  },
  {
    "path": "tsconfig.json",
    "chars": 323,
    "preview": "{\n  \"compilerOptions\": {\n    \"module\": \"ESNext\",\n    \"declaration\": true,\n    \"target\": \"ESNext\",\n    \"moduleResolution\""
  }
]

About this extraction

This page contains the full source code of the gvergnaud/ts-pattern GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 99 files (590.3 KB), approximately 167.6k tokens, and a symbol index with 1440 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!