Comments (3)
Well right after writing that all up I found a solution, by using type guards:
type Example<Value> = Bar<Value> | Foo<Value>
type Bar<Value> = { bar: Value }
type Foo<Value> = { foo: Value }
const isBar = <Value>(e: Example<Value>): e is Bar<Value> => 'bar' in e
const isFoo = <Value>(e: Example<Value>): e is Foo<Value> => 'foo' in e
const getValue = <Value>(e: Example<Value>): Value =>
match(e)
.when(isBar, ({ bar }) => bar as Value)
.when(isFoo, ({ foo }) => foo as Value)
.exhaustive()
The problem is those type guards aren't type-safe. If one of the keys are mistyped, or if one of the keys in the types change, or if one of the types are updated so that there's overlap, the compiler won't notice. Not sure how to fix that.
from ts-pattern.
The issue you are facing will only come up if you are matching on an unknown type parameter (Value
in your example). TS-Pattern will behave correctly if you instantiate Value
with a concrete type: Playground
import { match, P } from 'ts-pattern'
type Example<Value> =
| { foo: Value }
| { bar: Value }
// We instantiate `Example` with the `number` type.
// 👇
const getValue = (e: Example<number>): number => match(e)
.with({ foo: P.any }, ({ foo }) => foo) // ✅ works
.with({ bar: P.any }, ({ bar }) => bar) // ✅ works
.exhaustive()
The reason why is that TypeScript's type inference gets stuck on unknown type parameter. The type-level algorithm that ts-pattern uses to narrow the input type can't complete because expressions like Value extends number ? true : false
don't reduce to either true
or false
because TS doesn't know if Value
is assignable to number
or not.
the fact that TS-Pattern doesn't support generic types is a known limitation, but it's really a limitation of the language unfortunately.
My recommendation here is to use function signature overloads separate the public facing API of your function from the types it uses internally:
function getValue<T>(e: Example<T>): T;
function getValue(e: Example<unknown>): unknown {
return match(e)
.with({ foo: P.any }, ({ foo }) => foo)
.with({ bar: P.any }, ({ bar }) => bar)
.exhaustive()
}
I wrote about the reason I think this is the best option in this blog post: https://type-level-typescript.com/articles/making-generic-functions-pass-type-checking
from ts-pattern.
Related Issues (20)
- Type '"error"' is not assignable to type 'KnownPattern<"ok"> HOT 6
- Support Awaited<T>
- Many JSDoc examples are incorrect HOT 1
- Object with `any` breaks `.with` chaining HOT 2
- How do I return a string | null from a match HOT 2
- Nullish pattern doesn't work with omitted fields HOT 2
- Seemingly incorrect tuple maching types HOT 1
- Support type predicate return type at `.when()` callback HOT 4
- Type NonExhaustiveError<BoardDto> has no call signatures
- Preventing use of `.exhaustive()` for enum checks HOT 1
- Handle readonly arrays in .exhaustive() HOT 2
- Support point-free style HOT 3
- Select sub-type for exhaustive check. E.g. `.exhaustive(([state, event]) => event.type)`
- Handling of undefined typings in tuples HOT 1
- a way to split long match blocks
- Predicate factory HOT 3
- .safeExhaustive HOT 1
- Deconstruct string matched with `.startsWith`, `.endsWith`, `regex` HOT 2
- Enter multiple pipeline for objects type match HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from ts-pattern.