ts-pattern
Advanced tools
Comparing version 5.0.3 to 5.0.4
@@ -62,3 +62,3 @@ import type * as symbols from '../internals/symbols.js'; | ||
type KnownPattern<a> = KnownPatternInternal<a>; | ||
type KnownPatternInternal<a, objs = Exclude<a, Primitives | Map<any, any> | Set<any> | readonly any[]>, arrays = Extract<a, readonly any[]>, primitives = Exclude<a, object>> = primitives | PatternMatcher<a> | ([objs] extends [never] ? never : ObjectPattern<Readonly<MergeUnion<objs>>>) | ([arrays] extends [never] ? never : ArrayPattern<arrays>); | ||
type KnownPatternInternal<a, objs = Exclude<a, Primitives | Map<any, any> | Set<any> | readonly any[]>, arrays = Extract<a, readonly any[]>, primitives = Extract<a, Primitives>> = primitives | PatternMatcher<a> | ([objs] extends [never] ? never : ObjectPattern<Readonly<MergeUnion<objs>>>) | ([arrays] extends [never] ? never : ArrayPattern<arrays>); | ||
type ObjectPattern<a> = { | ||
@@ -65,0 +65,0 @@ readonly [k in keyof a]?: Pattern<a[k]>; |
{ | ||
"name": "ts-pattern", | ||
"version": "5.0.3", | ||
"version": "5.0.4", | ||
"description": " The exhaustive Pattern Matching library for TypeScript.", | ||
@@ -5,0 +5,0 @@ "type": "module", |
105
README.md
@@ -61,5 +61,5 @@ <h1 align="center">TS-Pattern</h1> | ||
[Pattern Matching](https://stackoverflow.com/questions/2502354/what-is-pattern-matching-in-functional-languages) is a code-branching technique coming from functional programming languages, which lets you scrutinize the structure of values in a declarative way. It has proven itself to be less verbose and more powerful than imperative alternatives (if/else/switch statements), especially when branching on complex data structures or on several values. | ||
[Pattern Matching](https://stackoverflow.com/questions/2502354/what-is-pattern-matching-in-functional-languages) 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 Haskell, Rust, Swift, Elixir and many other languages. There is [a tc39 proposal](https://github.com/tc39/proposal-pattern-matching) to add Pattern Matching to the EcmaScript specification, 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. | ||
Pattern Matching is implemented in Haskell, Rust, Swift, Elixir, 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. | ||
@@ -144,4 +144,3 @@ 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) | ||
As an example, we are going to create a state reducer for a | ||
frontend application fetching some data using an HTTP request. | ||
As an example, let's create a state reducer for a frontend application that fetches some data. | ||
@@ -175,8 +174,5 @@ ### Example: a state reducer with ts-pattern | ||
a request if we are currently in the `loading` state. | ||
To avoid unwanted state changes that could lead to bugs, we want to create | ||
a reducer function that **matches on both the state and the event** | ||
and return a new 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 do that in a very expressive way: | ||
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: | ||
@@ -187,24 +183,16 @@ <!-- prettier-ignore --> | ||
const reducer = (state: State, event: Event): State => | ||
match<[State, Event], State>([state, event]) | ||
const reducer = (state: State, event: Event) => | ||
match([state, event]) | ||
.returnType<State>() | ||
.with( | ||
[{ status: 'loading' }, { type: 'success' }], | ||
([, event]) => ({ | ||
status: 'success', | ||
data: event.data, | ||
}) | ||
([_, event]) => ({ status: 'success', data: event.data }) | ||
) | ||
.with( | ||
[{ status: 'loading' }, { type: 'error', error: P.select() }], | ||
(error) => ({ | ||
status: 'error', | ||
error, | ||
}) | ||
(error) => ({ status: 'error', error }) | ||
) | ||
.with( | ||
[{ status: P.not('loading') }, { type: 'fetch' }], | ||
() => ({ | ||
status: 'loading', | ||
startTime: Date.now(), | ||
}) | ||
() => ({ status: 'loading', startTime: Date.now() }) | ||
) | ||
@@ -219,5 +207,3 @@ .with( | ||
], | ||
() => ({ | ||
status: 'idle', | ||
}) | ||
() => ({ status: 'idle' }) | ||
) | ||
@@ -228,3 +214,3 @@ .with(P._, () => state) | ||
**Let's go through this bit by bit:** | ||
There's a lot going on, so **let's go through this code bit by bit:** | ||
@@ -235,15 +221,19 @@ ### match(value) | ||
<!-- prettier-ignore --> | ||
```ts | ||
match<[State, Event], State>([state, event]); | ||
match([state, event]) | ||
``` | ||
Here we wrap the state and the event objects in an array and we explicitly | ||
specify the type `[State, Event]` to make sure it is interpreted as | ||
a [Tuple](#tuples-arrays) by TypeScript, so we | ||
can match on each value separately. | ||
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. | ||
Most of the time, you don't need to specify the type of input | ||
and output with `match<Input, Output>(...)` because `match` is able to | ||
infer both of these types. | ||
### .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) | ||
@@ -265,7 +255,5 @@ | ||
The first argument is the **pattern**: the **shape of value** | ||
you expect for this branch. | ||
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 second argument is the **handler function**: the code **branch** that will be called if the input value matches the pattern. | ||
@@ -284,6 +272,3 @@ The handler function takes the input value as first parameter with its type **narrowed down** to what the pattern matches. | ||
], | ||
(error) => ({ | ||
status: 'error', | ||
error, | ||
}) | ||
(error) => ({ status: 'error', error }) | ||
) | ||
@@ -332,5 +317,3 @@ ``` | ||
[{ status: P.not('loading') }, { type: 'fetch' }], | ||
() => ({ | ||
status: 'loading', | ||
}) | ||
() => ({ status: 'loading' }) | ||
) | ||
@@ -341,7 +324,7 @@ ``` | ||
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 if a number is positive. In these cases, we can use **guard functions**: functions taking a value and returning a `boolean`. | ||
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 options to use a guard function: | ||
With TS-Pattern, there are two ways to use a guard function: | ||
- use `P.when(<guard function>)` inside your pattern | ||
- use `P.when(<guard function>)` inside one of your patterns | ||
- pass it as second parameter to `.with(...)` | ||
@@ -360,5 +343,3 @@ | ||
], | ||
() => ({ | ||
status: 'idle', | ||
}) | ||
() => ({ status: 'idle' }) | ||
) | ||
@@ -376,5 +357,3 @@ ``` | ||
([state, event]) => state.startTime + 2000 < Date.now(), | ||
() => ({ | ||
status: 'idle' | ||
}) | ||
() => ({ status: 'idle' }) | ||
) | ||
@@ -408,5 +387,5 @@ ``` | ||
Note that exhaustive pattern matching is **optional**. It comes with the trade-off of having **longer compilation times** because the type checker has more work to do. | ||
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()`. | ||
Alternatively, you can use `.otherwise()`, which takes an handler function returning a default value. `.otherwise(handler)` is equivalent to `.with(P._, handler).exhaustive()`. | ||
@@ -417,10 +396,2 @@ ```ts | ||
If you don't want to use `.exhaustive()` and also don't want to provide a default value with `.otherwise()`, you can use `.run()` instead: | ||
```ts | ||
.run(); | ||
``` | ||
It's just like `.exhaustive()`, but it's **unsafe** and might throw runtime error if no branch matches your input value. | ||
### Matching several patterns | ||
@@ -598,3 +569,3 @@ | ||
```ts | ||
function exhaustive(): IOutput; | ||
function exhaustive(): TOutput; | ||
``` | ||
@@ -658,3 +629,3 @@ | ||
Runs the pattern-matching expression and returns its result. It throws an error at run time if no match was found, same as `exhaustive()`. However, unlike `.exhaustive()`, exhaustiveness is not checked at compile time, meaning the type checker will not verify that all possible cases are covered. | ||
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. | ||
@@ -661,0 +632,0 @@ #### Signature |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
418486
1627