ts-pattern
Advanced tools
Comparing version 0.1.3 to 0.1.4
@@ -13,3 +13,15 @@ /** | ||
* ### Catch All wildcard | ||
* `__` refers to a wildcard pattern, matching any value | ||
* `__` is wildcard pattern, matching **any value**. | ||
* | ||
* `__.string` is wildcard pattern matching any **string**. | ||
* | ||
* `__.number` is wildcard pattern matching any **number**. | ||
* | ||
* `__.boolean` is wildcard pattern matching any **boolean**. | ||
* @example | ||
* match(value) | ||
* .with(__, () => 'will always match') | ||
* .with(__.string, () => 'will match on strings only') | ||
* .with(__.number, () => 'will match on numbers only') | ||
* .with(__.boolean, () => 'will match on booleans only') | ||
*/ | ||
@@ -53,3 +65,3 @@ export declare const __: { | ||
valueKind: PatternType.Not; | ||
pattern: InvertPattern<pb>; | ||
value: InvertPattern<pb>; | ||
} : p extends Primitives ? p : p extends [infer pb, infer pc, infer pd, infer pe, infer pf] ? [InvertPattern<pb>, InvertPattern<pc>, InvertPattern<pd>, InvertPattern<pe>, InvertPattern<pf>] : p extends [infer pb, infer pc, infer pd, infer pe] ? [InvertPattern<pb>, InvertPattern<pc>, InvertPattern<pd>, InvertPattern<pe>] : p extends [infer pb, infer pc, infer pd] ? [InvertPattern<pb>, InvertPattern<pc>, InvertPattern<pd>] : p extends [infer pb, infer pc] ? [InvertPattern<pb>, InvertPattern<pc>] : p extends (infer pp)[] ? InvertPattern<pp>[] : p extends Map<infer pk, infer pv> ? Map<pk, InvertPattern<pv>> : p extends Set<infer pv> ? Set<InvertPattern<pv>> : p extends object ? { | ||
@@ -69,4 +81,4 @@ [k in keyof p]: InvertPattern<p[k]>; | ||
valueKind: PatternType.Not; | ||
pattern: infer b1; | ||
} ? Exclude<a, b1> : [a, b] extends [object, object] ? ObjectExtractMostPreciseValue<a, b> : LeastUpperBound<a, b>; | ||
value: infer b1; | ||
} ? Exclude<a, b1> extends never ? a : Exclude<a, b1> : b extends object ? ObjectExtractMostPreciseValue<a, b> : LeastUpperBound<a, b>; | ||
/** | ||
@@ -73,0 +85,0 @@ * if a key of an object has the never type, |
@@ -37,3 +37,15 @@ "use strict"; | ||
* ### Catch All wildcard | ||
* `__` refers to a wildcard pattern, matching any value | ||
* `__` is wildcard pattern, matching **any value**. | ||
* | ||
* `__.string` is wildcard pattern matching any **string**. | ||
* | ||
* `__.number` is wildcard pattern matching any **number**. | ||
* | ||
* `__.boolean` is wildcard pattern matching any **boolean**. | ||
* @example | ||
* match(value) | ||
* .with(__, () => 'will always match') | ||
* .with(__.string, () => 'will match on strings only') | ||
* .with(__.number, () => 'will match on numbers only') | ||
* .with(__.boolean, () => 'will match on booleans only') | ||
*/ | ||
@@ -40,0 +52,0 @@ exports.__ = { |
{ | ||
"name": "ts-pattern", | ||
"version": "0.1.3", | ||
"version": "0.1.4", | ||
"description": "Typescript pattern matching library", | ||
@@ -5,0 +5,0 @@ "main": "lib/index.js", |
@@ -8,18 +8,23 @@ # Typescript Pattern | ||
match({ type: 'hello' }) | ||
.with(__, () => 'ok') | ||
.with(__.string, () => 'ok') | ||
type Input = { type: string } | string; | ||
match<Input, 'ok'>({ type: 'hello' }) | ||
.with(__, (value) => 'ok') // value: Input | ||
.with(__.string, (value) => 'ok') // value: string | ||
.with( | ||
when((x) => true), | ||
() => 'ok' | ||
when((value) => true), | ||
(value) => 'ok' // value: Input | ||
) | ||
.with(not('hello'), () => 'ok') | ||
.with(not(__.string), () => 'ok') | ||
.with(not(when((x) => true)), () => 'ok') | ||
.with({ type: __ }, () => 'ok') | ||
.with({ type: __.string }, () => 'ok') | ||
.with({ type: when((x) => true) }, () => 'ok') | ||
.with({ type: not('hello') }, () => 'ok') | ||
.with({ type: not(__.string) }, () => 'ok') | ||
.with({ type: not(when((x) => true)) }, () => 'ok'); | ||
.with(not('hello'), (value) => 'ok') // value: Input | ||
.with(not(__.string), (value) => 'ok') // value: { type: string } | ||
.with(not(when(() => true)), (value) => 'ok') // value: Input | ||
.with({ type: __ }, (value) => 'ok') // value: { type: string } | ||
.with({ type: __.string }, (value) => 'ok') // value: { type: string } | ||
.with({ type: when(() => true) }, (value) => 'ok') // value: { type: string } | ||
.with({ type: not('hello' as 'hello') }, (value) => 'ok') // value: { type: string } | ||
.with({ type: not(__.string) }, (value) => 'ok') // value: { type: string } | ||
.with({ type: not(when(() => true)) }, (value) => 'ok') // value: { type: string } | ||
.with(not({ type: when(() => true) }), (value) => 'ok') // value: string | ||
.with(not({ type: __.string }), (value) => 'ok') // value: string | ||
.run(); | ||
``` |
@@ -15,3 +15,15 @@ /** | ||
* ### Catch All wildcard | ||
* `__` refers to a wildcard pattern, matching any value | ||
* `__` is wildcard pattern, matching **any value**. | ||
* | ||
* `__.string` is wildcard pattern matching any **string**. | ||
* | ||
* `__.number` is wildcard pattern matching any **number**. | ||
* | ||
* `__.boolean` is wildcard pattern matching any **boolean**. | ||
* @example | ||
* match(value) | ||
* .with(__, () => 'will always match') | ||
* .with(__.string, () => 'will match on strings only') | ||
* .with(__.number, () => 'will match on numbers only') | ||
* .with(__.boolean, () => 'will match on booleans only') | ||
*/ | ||
@@ -112,3 +124,3 @@ export const __ = { | ||
valueKind: PatternType.Not; | ||
pattern: InvertPattern<pb>; | ||
value: InvertPattern<pb>; | ||
} | ||
@@ -192,5 +204,7 @@ : p extends Primitives | ||
? a | ||
: b extends { valueKind: PatternType.Not; pattern: infer b1 } | ||
? Exclude<a, b1> | ||
: [a, b] extends [object, object] | ||
: b extends { valueKind: PatternType.Not; value: infer b1 } | ||
? Exclude<a, b1> extends never | ||
? a | ||
: Exclude<a, b1> | ||
: b extends object | ||
? ObjectExtractMostPreciseValue<a, b> | ||
@@ -197,0 +211,0 @@ : LeastUpperBound<a, b>; |
import { match, __, when, not, Pattern } from '../src'; | ||
// the never type can be assigned to anything. This type prevent that | ||
type NotNever<a> = a extends never ? never : true; | ||
type Option<a> = { kind: 'none' } | { kind: 'some'; value: a }; | ||
@@ -43,2 +46,3 @@ | ||
const pattern2: Pattern<Input> = when((x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: Input = x; | ||
@@ -50,2 +54,3 @@ return true; | ||
when((state) => { | ||
const notNever: NotNever<typeof state> = true; | ||
const inferenceCheck: State = state; | ||
@@ -55,2 +60,3 @@ return !!state; | ||
when((event) => { | ||
const notNever: NotNever<typeof event> = true; | ||
const inferenceCheck: Event = event; | ||
@@ -70,2 +76,3 @@ return !!event; | ||
data: when((d) => { | ||
const notNever: NotNever<typeof d> = true; | ||
const inferenceCheck: string = d; | ||
@@ -91,2 +98,3 @@ return true; | ||
x: when((x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: string = x; | ||
@@ -100,2 +108,3 @@ return true; | ||
x: when((x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: string = x; | ||
@@ -110,2 +119,3 @@ return true; | ||
x: when((x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: string = x; | ||
@@ -117,2 +127,3 @@ return true; | ||
y: when((y) => { | ||
const notNever: NotNever<typeof y> = true; | ||
const inferenceCheck: number = y; | ||
@@ -125,2 +136,3 @@ return true; | ||
const pattern10: Pattern<string | number> = when((x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: string | number = x; | ||
@@ -130,2 +142,94 @@ return true; | ||
}); | ||
it('should infer values correctly in handler', () => { | ||
type Input = { type: string } | string; | ||
match<Input, 'ok'>({ type: 'hello' }) | ||
.with(__, (x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: Input = x; | ||
return 'ok'; | ||
}) | ||
.with(__.string, (x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: string = x; | ||
return 'ok'; | ||
}) | ||
.with( | ||
when((x) => true), | ||
(x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: Input = x; | ||
return 'ok'; | ||
} | ||
) | ||
.with(not('hello'), (x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: Input = x; | ||
return 'ok'; | ||
}) | ||
.with(not(__.string), (x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: { type: string } = x; | ||
return 'ok'; | ||
}) | ||
.with(not(when((x) => true)), (x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: Input = x; | ||
return 'ok'; | ||
}) | ||
.with({ type: __ }, (x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: { type: string } = x; | ||
return 'ok'; | ||
}) | ||
.with({ type: __.string }, (x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: { type: string } = x; | ||
return 'ok'; | ||
}) | ||
.with({ type: when((x) => true) }, (x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: { type: string } = x; | ||
return 'ok'; | ||
}) | ||
.with({ type: not('hello' as 'hello') }, (x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: { type: string } = x; | ||
return 'ok'; | ||
}) | ||
.with({ type: not(__.string) }, (x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: { type: string } = x; | ||
return 'ok'; | ||
}) | ||
.with({ type: not(when((x) => true)) }, (x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: { type: string } = x; | ||
return 'ok'; | ||
}) | ||
.with(not({ type: when((x: string) => true) }), (x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: Input = x; | ||
return 'ok'; | ||
}) | ||
.with(not({ type: __.string }), (x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: string = x; | ||
return 'ok'; | ||
}) | ||
.run(); | ||
}); | ||
it('a union of object or primitive should be matched with a correct type inference', () => { | ||
type Input = { type: string } | string; | ||
match<Input, 'ok'>({ type: 'hello' }) | ||
.with({ type: __ }, (x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: { type: string } = x; | ||
return 'ok'; | ||
}) | ||
.run(); | ||
}); | ||
}); | ||
@@ -139,2 +243,3 @@ | ||
.with(1, (v) => { | ||
const notNever: NotNever<typeof v> = true; | ||
const inferenceCheck: 1 = v; | ||
@@ -144,2 +249,3 @@ return v * 2; | ||
.with(2, (v) => { | ||
const notNever: NotNever<typeof v> = true; | ||
const inferenceCheck: 2 = v; | ||
@@ -170,2 +276,3 @@ return v * v; | ||
.with({ x: 1, y: 1, z: 1 }, (x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: Vector3 = x; | ||
@@ -175,2 +282,3 @@ return 'vector3'; | ||
.with({ x: 2, y: 1 }, (x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: Vector2 = x; | ||
@@ -180,2 +288,3 @@ return 'vector2'; | ||
.with({ x: 1 }, (x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: Vector1 = x; | ||
@@ -200,2 +309,3 @@ return 'vector1'; | ||
.with({ kind: 'some' }, (o) => { | ||
const notNever: NotNever<typeof o> = true; | ||
const inferenceCheck: { kind: 'some'; value: string } = o; | ||
@@ -217,2 +327,3 @@ return o.value; | ||
.with([], (x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: never[] = x; | ||
@@ -222,2 +333,3 @@ return { kind: 'some', value: [{ id: 0, title: 'LOlol' }] }; | ||
.with([{ id: __.number, title: __.string }], (blogs) => { | ||
const notNever: NotNever<typeof blogs> = true; | ||
const inferenceCheck: { id: number; title: string }[] = blogs; | ||
@@ -230,2 +342,3 @@ return { | ||
.with(20, (x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: number = x; | ||
@@ -270,2 +383,3 @@ return { kind: 'none' }; | ||
.with(['hello', 20], (x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: [string, number] = x; | ||
@@ -275,2 +389,3 @@ return `perfect match`; | ||
.with(['hello', __], (x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: [string, number] = x; | ||
@@ -280,2 +395,3 @@ return `string match`; | ||
.with([__, 20], (x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: [string, number] = x; | ||
@@ -285,2 +401,3 @@ return `number match`; | ||
.with([__.string, __.number], (x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: [string, number] = x; | ||
@@ -290,2 +407,3 @@ return `not matching`; | ||
.with([__, __], (x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: [string, number] = x; | ||
@@ -295,2 +413,3 @@ return `can't happen`; | ||
.with(__, (x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: [string, number] = x; | ||
@@ -385,2 +504,3 @@ return `can't happen`; | ||
.with(new Set(['gab', 'yo']), (x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: Set<string> = x; | ||
@@ -390,2 +510,3 @@ return [true, true]; | ||
.with(new Set(['gab']), (x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: Set<string> = x; | ||
@@ -395,2 +516,3 @@ return [true, false]; | ||
.with(new Set(['yo']), (x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: Set<string> = x; | ||
@@ -400,2 +522,3 @@ return [false, true]; | ||
.with(__, (x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: Set<string | number> = x; | ||
@@ -424,2 +547,41 @@ return [false, false]; | ||
describe('wildcards', () => { | ||
it('should match String wildcards', () => { | ||
const res = match<string | number | boolean, boolean>('') | ||
.with(__.string, (x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: string = x; | ||
return true; | ||
}) | ||
.otherwise(() => false) | ||
.run(); | ||
expect(res).toEqual(true); | ||
}); | ||
it('should match Number wildcards', () => { | ||
const res = match<string | number | boolean, boolean>(2) | ||
.with(__.number, (x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: number = x; | ||
return true; | ||
}) | ||
.otherwise(() => false) | ||
.run(); | ||
expect(res).toEqual(true); | ||
}); | ||
it('should match Boolean wildcards', () => { | ||
const res = match<string | number | boolean, boolean>(true) | ||
.with(__.boolean, (x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: boolean = x; | ||
return true; | ||
}) | ||
.otherwise(() => false) | ||
.run(); | ||
expect(res).toEqual(true); | ||
}); | ||
it('should match String, Number and Boolean wildcards', () => { | ||
@@ -446,2 +608,41 @@ // Will be { id: number, title: string } | { errorMessage: string } | ||
}); | ||
it('should infer correctly negated String wildcards', () => { | ||
const res = match<string | number | boolean, boolean>('') | ||
.with(not(__.string), (x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: number | boolean = x; | ||
return true; | ||
}) | ||
.otherwise(() => false) | ||
.run(); | ||
expect(res).toEqual(false); | ||
}); | ||
it('should infer correctly negated Number wildcards', () => { | ||
const res = match<string | number | boolean, boolean>(2) | ||
.with(not(__.number), (x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: string | boolean = x; | ||
return true; | ||
}) | ||
.otherwise(() => false) | ||
.run(); | ||
expect(res).toEqual(false); | ||
}); | ||
it('should infer correctly negated Boolean wildcards', () => { | ||
const res = match<string | number | boolean, boolean>(true) | ||
.with(not(__.boolean), (x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: string | number = x; | ||
return true; | ||
}) | ||
.otherwise(() => false) | ||
.run(); | ||
expect(res).toEqual(false); | ||
}); | ||
}); | ||
@@ -505,2 +706,3 @@ | ||
(x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: 13 = x; | ||
@@ -513,2 +715,3 @@ return true; | ||
const notNever: NotNever<typeof res> = true; | ||
const inferenceCheck: boolean = res; | ||
@@ -534,2 +737,3 @@ }); | ||
(x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: { status: 'success'; data: string } = x; | ||
@@ -556,2 +760,3 @@ return true; | ||
x: when((x): x is 20 => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: number = x; | ||
@@ -563,2 +768,3 @@ return x === 20; | ||
(vec) => { | ||
const notNever: NotNever<typeof vec> = true; | ||
const inferenceCheck: Vec3 = vec; | ||
@@ -571,2 +777,3 @@ return vec.y > 2; | ||
(x) => { | ||
const notNever: NotNever<typeof vec> = true; | ||
const inferenceCheck: Vec3 = vec; | ||
@@ -588,2 +795,3 @@ return false; | ||
.with(not(__.number), (x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: unknown = x; | ||
@@ -593,2 +801,3 @@ return 'not a number'; | ||
.with(not(__.string), (x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: unknown = x; | ||
@@ -608,2 +817,3 @@ return 'not a string'; | ||
.with({ y: __.number, x: not(__.string) }, (x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: { x: number; y: number } = x; | ||
@@ -626,2 +836,3 @@ return 'yes'; | ||
.with(not(one), (x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: 'two' = x; | ||
@@ -631,2 +842,3 @@ return 'not 1'; | ||
.with(not(two), (x) => { | ||
const notNever: NotNever<typeof x> = true; | ||
const inferenceCheck: 'one' = x; | ||
@@ -633,0 +845,0 @@ return 'not 2'; |
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
53733
1464
30