ts-pattern
Advanced tools
Comparing version 1.1.0 to 2.0.1-next.0
@@ -1,7 +0,12 @@ | ||
import { Pattern, __, when, not, select } from './types/Pattern'; | ||
import { Match } from './types/Match'; | ||
import type { Pattern, SelectPattern, GuardPattern, NotPattern, GuardFunction } from './types/Pattern'; | ||
import type { Match, ExhaustiveMatch } from './types/Match'; | ||
import { __ } from './PatternType'; | ||
import { DistributeUnions } from './types/DistributeUnions'; | ||
export declare const when: <a, b extends a = a>(predicate: GuardFunction<a, b>) => GuardPattern<a, b>; | ||
export declare const not: <a>(pattern: Pattern<a>) => NotPattern<a>; | ||
export declare const select: <k extends string>(key: k) => SelectPattern<k>; | ||
/** | ||
* # Pattern matching | ||
**/ | ||
export { Pattern, __, when, not, select }; | ||
export { Pattern, __ }; | ||
/** | ||
@@ -13,1 +18,8 @@ * ### match | ||
export declare const match: <a, b = "@match/unset">(value: a) => Match<a, b>; | ||
/** | ||
* ### exhaustiveMatch | ||
* creates an exhaustive match expression checking | ||
* that **all cases are handled**. `when` predicates | ||
* aren't supported on exhaustive matches. | ||
**/ | ||
export declare const exhaustiveMatch: <a, b = "@match/unset">(value: a) => ExhaustiveMatch<DistributeUnions<a>, b>; |
@@ -23,8 +23,20 @@ "use strict"; | ||
exports.__esModule = true; | ||
exports.match = exports.select = exports.not = exports.when = exports.__ = void 0; | ||
var Pattern_1 = require("./types/Pattern"); | ||
exports.__ = Pattern_1.__; | ||
exports.when = Pattern_1.when; | ||
exports.not = Pattern_1.not; | ||
exports.select = Pattern_1.select; | ||
exports.exhaustiveMatch = exports.match = exports.__ = exports.select = exports.not = exports.when = void 0; | ||
var PatternType_1 = require("./PatternType"); | ||
exports.__ = PatternType_1.__; | ||
var when = function (predicate) { return ({ | ||
__patternKind: PatternType_1.PatternType.Guard, | ||
__when: predicate | ||
}); }; | ||
exports.when = when; | ||
var not = function (pattern) { return ({ | ||
__patternKind: PatternType_1.PatternType.Not, | ||
__pattern: pattern | ||
}); }; | ||
exports.not = not; | ||
var select = function (key) { return ({ | ||
__patternKind: PatternType_1.PatternType.Select, | ||
__key: key | ||
}); }; | ||
exports.select = select; | ||
/** | ||
@@ -35,6 +47,15 @@ * ### match | ||
*/ | ||
exports.match = function (value) { | ||
var match = function (value) { | ||
return builder(value, []); | ||
}; | ||
exports.match = match; | ||
/** | ||
* ### exhaustiveMatch | ||
* creates an exhaustive match expression checking | ||
* that **all cases are handled**. `when` predicates | ||
* aren't supported on exhaustive matches. | ||
**/ | ||
var exhaustiveMatch = function (value) { return builder(value, []); }; | ||
exports.exhaustiveMatch = exhaustiveMatch; | ||
/** | ||
* ### builder | ||
@@ -78,3 +99,3 @@ * This is the implementation of our pattern matching, using the | ||
{ | ||
test: matchPattern(Pattern_1.__), | ||
test: matchPattern(PatternType_1.__), | ||
handler: handler, | ||
@@ -91,3 +112,10 @@ select: function () { return ({}); } | ||
if (!entry) { | ||
throw new Error("Pattern matching error: no pattern matches value " + value); | ||
var displayedValue = void 0; | ||
try { | ||
displayedValue = JSON.stringify(value); | ||
} | ||
catch (e) { | ||
displayedValue = value; | ||
} | ||
throw new Error("Pattern matching error: no pattern matches value " + displayedValue); | ||
} | ||
@@ -98,8 +126,9 @@ return entry.handler(value, entry.select(value)); | ||
var isObject = function (value) { | ||
return value && typeof value === 'object'; | ||
return Boolean(value && typeof value === 'object'); | ||
}; | ||
var isArray = function (value) { return Array.isArray(value); }; | ||
var isGuardPattern = function (x) { | ||
var pattern = x; | ||
return (pattern && | ||
pattern.__patternKind === Pattern_1.PatternType.Guard && | ||
pattern.__patternKind === PatternType_1.PatternType.Guard && | ||
typeof pattern.__when === 'function'); | ||
@@ -109,7 +138,7 @@ }; | ||
var pattern = x; | ||
return pattern && pattern.__patternKind === Pattern_1.PatternType.Not; | ||
return pattern && pattern.__patternKind === PatternType_1.PatternType.Not; | ||
}; | ||
var isSelectPattern = function (x) { | ||
var pattern = x; | ||
return pattern && pattern.__patternKind === Pattern_1.PatternType.Select; | ||
return pattern && pattern.__patternKind === PatternType_1.PatternType.Select; | ||
}; | ||
@@ -121,9 +150,9 @@ var isListPattern = function (x) { | ||
var matchPattern = function (pattern) { return function (value) { | ||
if (pattern === Pattern_1.__ || isSelectPattern(pattern)) | ||
if (pattern === PatternType_1.__ || isSelectPattern(pattern)) | ||
return true; | ||
if (pattern === Pattern_1.__.string) | ||
if (pattern === PatternType_1.__.string) | ||
return typeof value === 'string'; | ||
if (pattern === Pattern_1.__.boolean) | ||
if (pattern === PatternType_1.__.boolean) | ||
return typeof value === 'boolean'; | ||
if (pattern === Pattern_1.__.number) { | ||
if (pattern === PatternType_1.__.number) { | ||
return typeof value === 'number' && !Number.isNaN(value); | ||
@@ -135,7 +164,7 @@ } | ||
return !matchPattern(pattern.__pattern)(value); | ||
if (isListPattern(pattern) && Array.isArray(value)) | ||
if (isListPattern(pattern) && isArray(value)) | ||
return value.every(function (v) { return matchPattern(pattern[0])(v); }); | ||
if (typeof pattern !== typeof value) | ||
return false; | ||
if (Array.isArray(pattern) && Array.isArray(value)) { | ||
if (isArray(pattern) && isArray(value)) { | ||
return pattern.length === value.length | ||
@@ -157,3 +186,3 @@ ? pattern.every(function (subPattern, i) { return matchPattern(subPattern)(value[i]); }) | ||
? patternValues.every(function (subPattern) { | ||
return Object.values(Pattern_1.__).includes(subPattern) | ||
return Object.values(PatternType_1.__).includes(subPattern) | ||
? matchPattern([subPattern])(allValues_1) | ||
@@ -176,3 +205,3 @@ : value.has(subPattern); | ||
return _a = {}, _a[pattern.__key] = value, _a; | ||
if (isListPattern(pattern) && Array.isArray(value)) | ||
if (isListPattern(pattern) && isArray(value)) | ||
return value | ||
@@ -186,3 +215,3 @@ .map(function (v) { return selectWithPattern(pattern[0])(v); }) | ||
}, {}); | ||
if (Array.isArray(pattern) && Array.isArray(value)) | ||
if (isArray(pattern) && isArray(value)) | ||
return pattern.length <= value.length | ||
@@ -189,0 +218,0 @@ ? pattern.reduce(function (acc, subPattern, i) { |
@@ -1,8 +0,24 @@ | ||
import { PatternType, __, Primitives } from './Pattern'; | ||
import { ExcludeIfContainsNever, LeastUpperBound } from './helpers'; | ||
import type { PatternType, __ } from '../PatternType'; | ||
import type { Primitives } from './Pattern'; | ||
import type { ExcludeIfContainsNever, LeastUpperBound } from './helpers'; | ||
export declare type ExtractPreciseValue<a, b> = ExcludeIfContainsNever<b extends [] ? [] : b extends typeof __ ? a : b extends { | ||
valueKind: PatternType.Not; | ||
value: infer b1; | ||
} ? Exclude<a, b1> : b extends [infer b1, infer b2, infer b3, infer b4, infer b5] ? a extends [infer a1, infer a2, infer a3, infer a4, infer a5] ? [ExtractPreciseValue<a1, b1>, ExtractPreciseValue<a2, b2>, ExtractPreciseValue<a3, b3>, ExtractPreciseValue<a4, b4>, ExtractPreciseValue<a5, b5>] : LeastUpperBound<a, b> : b extends [infer b1, infer b2, infer b3, infer b4] ? a extends [infer a1, infer a2, infer a3, infer a4] ? [ExtractPreciseValue<a1, b1>, ExtractPreciseValue<a2, b2>, ExtractPreciseValue<a3, b3>, ExtractPreciseValue<a4, b4>] : LeastUpperBound<a, b> : b extends [infer b1, infer b2, infer b3] ? a extends [infer a1, infer a2, infer a3] ? [ExtractPreciseValue<a1, b1>, ExtractPreciseValue<a2, b2>, ExtractPreciseValue<a3, b3>] : LeastUpperBound<a, b> : b extends [infer b1, infer b2] ? a extends [infer a1, infer a2] ? [ExtractPreciseValue<a1, b1>, ExtractPreciseValue<a2, b2>] : LeastUpperBound<a, b> : b extends (infer b1)[] ? a extends (infer a1)[] ? ExtractPreciseValue<a1, b1>[] : LeastUpperBound<a, b> : 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> : b extends object ? a extends any[] | Set<any> | Map<any, any> | Primitives ? LeastUpperBound<a, b> : b extends a ? b : a extends b ? a : { | ||
} ? Exclude<a, b1> : b extends [infer b1, infer b2, infer b3, infer b4, infer b5] ? a extends [infer a1, infer a2, infer a3, infer a4, infer a5] ? [ | ||
ExtractPreciseValue<a1, b1>, | ||
ExtractPreciseValue<a2, b2>, | ||
ExtractPreciseValue<a3, b3>, | ||
ExtractPreciseValue<a4, b4>, | ||
ExtractPreciseValue<a5, b5> | ||
] : LeastUpperBound<a, b> : b extends [infer b1, infer b2, infer b3, infer b4] ? a extends [infer a1, infer a2, infer a3, infer a4] ? [ | ||
ExtractPreciseValue<a1, b1>, | ||
ExtractPreciseValue<a2, b2>, | ||
ExtractPreciseValue<a3, b3>, | ||
ExtractPreciseValue<a4, b4> | ||
] : LeastUpperBound<a, b> : b extends [infer b1, infer b2, infer b3] ? a extends [infer a1, infer a2, infer a3] ? [ | ||
ExtractPreciseValue<a1, b1>, | ||
ExtractPreciseValue<a2, b2>, | ||
ExtractPreciseValue<a3, b3> | ||
] : LeastUpperBound<a, b> : b extends [infer b1, infer b2] ? a extends [infer a1, infer a2] ? [ExtractPreciseValue<a1, b1>, ExtractPreciseValue<a2, b2>] : LeastUpperBound<a, b> : b extends (infer b1)[] ? a extends (infer a1)[] ? ExtractPreciseValue<a1, b1>[] : LeastUpperBound<a, b> : 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> : b extends object ? a extends any[] | Set<any> | Map<any, any> | Primitives ? LeastUpperBound<a, b> : b extends a ? b : a extends b ? a : { | ||
[k in keyof Required<a>]: k extends keyof b ? ExtractPreciseValue<a[k], b[k]> : a[k]; | ||
} : LeastUpperBound<a, b>>; |
@@ -1,2 +0,3 @@ | ||
export declare type ValueOf<a> = a[keyof a]; | ||
export declare type ValueOf<a> = a extends any[] ? a[number] : a[keyof a]; | ||
export declare type Values<a extends object> = UnionToTuple<ValueOf<a>>; | ||
/** | ||
@@ -21,2 +22,29 @@ * ### LeastUpperBound | ||
export declare type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never; | ||
declare type IsLiteralString<T extends string> = string extends T ? false : true; | ||
declare type IsLiteralNumber<T extends number> = number extends T ? false : true; | ||
declare type IsLiteralBoolean<T extends boolean> = boolean extends T ? false : true; | ||
export declare type IsLiteral<T> = T extends string ? IsLiteralString<T> : T extends number ? IsLiteralNumber<T> : T extends boolean ? IsLiteralBoolean<T> : false; | ||
export declare type IsUnion<a> = [a] extends [UnionToIntersection<a>] ? false : true; | ||
export declare type ContainsUnion<a> = IsUnion<a> extends true ? true : a extends object ? false extends ValueOf<{ | ||
[k in keyof a]: ContainsUnion<a[k]>; | ||
}> ? false : true : false; | ||
declare type NeverKeys<o> = ValueOf<{ | ||
[k in keyof o]: [o[k]] extends [never] ? k : never; | ||
}>; | ||
declare type RemoveNeverKeys<o> = Omit<o, NeverKeys<o>>; | ||
export declare type ExcludeUnion<a> = IsUnion<a> extends true ? never : a extends object ? RemoveNeverKeys<{ | ||
[k in keyof a]: ExcludeUnion<a[k]>; | ||
}> : a; | ||
export declare type UnionToTuple<T> = UnionToIntersection<T extends any ? (t: T) => T : never> extends (_: any) => infer W ? [...UnionToTuple<Exclude<T, W>>, W] : []; | ||
export declare type Cast<a, b> = a extends b ? a : never; | ||
export declare type Flatten<xs extends any[]> = xs extends [infer head, ...(infer tail)] ? [...Cast<head, any[]>, ...Flatten<tail>] : []; | ||
export declare type Equal<X, Y> = X extends Y ? (Y extends X ? true : false) : false; | ||
export declare type Expect<T extends true> = T; | ||
export declare type IsAny<a> = [a] extends [never] ? false : Equal<a, any>; | ||
export declare type Length<it extends any[]> = it['length']; | ||
export declare type Iterator<n extends number, it extends any[] = []> = it['length'] extends n ? it : Iterator<n, [any, ...it]>; | ||
export declare type Next<it extends any[]> = [any, ...it]; | ||
export declare type Prev<it extends any[]> = it extends [any, ...(infer tail)] ? tail : []; | ||
export declare type Slice<xs extends any[], it extends any[], output extends any[] = []> = Length<it> extends 0 ? output : xs extends [infer head, ...(infer tail)] ? Slice<tail, Prev<it>, [...output, head]> : output; | ||
export declare type Drop<xs extends any[], n extends any[]> = Length<n> extends 0 ? xs : xs extends [any, ...(infer tail)] ? Drop<tail, Prev<n>> : []; | ||
export {}; |
@@ -1,2 +0,3 @@ | ||
import { __, SelectPattern, GuardPattern, NotPattern, PatternType, Primitives } from './Pattern'; | ||
import type { PatternType, __ } from '../PatternType'; | ||
import type { SelectPattern, GuardPattern, NotPattern, Primitives } from './Pattern'; | ||
/** | ||
@@ -10,4 +11,10 @@ * ### InvertPattern | ||
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 ? { | ||
} : 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 ? { | ||
[k in keyof p]: InvertPattern<p[k]>; | ||
} : p; |
@@ -1,37 +0,7 @@ | ||
import { Pattern, SelectPattern, GuardValue } from './Pattern'; | ||
import { ExtractPreciseValue } from './ExtractPreciseValue'; | ||
import { InvertPattern } from './InvertPattern'; | ||
import { ValueOf, UnionToIntersection } from './helpers'; | ||
import type { Pattern, GuardValue, ExhaustivePattern } from './Pattern'; | ||
import type { ExtractPreciseValue } from './ExtractPreciseValue'; | ||
import type { InvertPattern } from './InvertPattern'; | ||
import type { UnionToIntersection } from './helpers'; | ||
import type { FindSelected } from './FindSelected'; | ||
export declare type MatchedValue<a, p extends Pattern<a>> = ExtractPreciseValue<a, InvertPattern<p>> extends never ? a : ExtractPreciseValue<a, InvertPattern<p>>; | ||
declare type FindSelected<a, b> = b extends SelectPattern<infer Key> ? { | ||
[k in Key]: a; | ||
} : [a, b] extends [(infer aa)[], [infer p]] ? { | ||
[k in keyof FindSelected1<aa, p>]: FindSelected1<aa, p>[k][]; | ||
} : [a, b] extends [object, object] ? ValueOf<{ | ||
[k in keyof a & keyof b]: FindSelected1<a[k], b[k]>; | ||
}> : never; | ||
declare type FindSelected1<a, b> = b extends SelectPattern<infer Key> ? { | ||
[k in Key]: a; | ||
} : [a, b] extends [(infer aa)[], [infer p]] ? { | ||
[k in keyof FindSelected2<aa, p>]: FindSelected2<aa, p>[k][]; | ||
} : [a, b] extends [object, object] ? ValueOf<{ | ||
[k in keyof a & keyof b]: FindSelected2<a[k], b[k]>; | ||
}> : never; | ||
declare type FindSelected2<a, b> = b extends SelectPattern<infer Key> ? { | ||
[k in Key]: a; | ||
} : [a, b] extends [(infer aa)[], [infer p]] ? { | ||
[k in keyof FindSelected3<aa, p>]: FindSelected3<aa, p>[k][]; | ||
} : [a, b] extends [object, object] ? ValueOf<{ | ||
[k in keyof a & keyof b]: FindSelected3<a[k], b[k]>; | ||
}> : never; | ||
declare type FindSelected3<a, b> = b extends SelectPattern<infer Key> ? { | ||
[k in Key]: a; | ||
} : [a, b] extends [(infer aa)[], [infer p]] ? { | ||
[k in keyof FindSelected4<aa, p>]: FindSelected4<aa, p>[k][]; | ||
} : [a, b] extends [object, object] ? ValueOf<{ | ||
[k in keyof a & keyof b]: FindSelected4<a[k], b[k]>; | ||
}> : never; | ||
declare type FindSelected4<a, b> = b extends SelectPattern<infer Key> ? { | ||
[k in Key]: a; | ||
} : never; | ||
export declare type ExtractSelections<a, p extends Pattern<a>> = UnionToIntersection<FindSelected<MatchedValue<a, p>, p>>; | ||
@@ -74,2 +44,34 @@ export declare type Unset = '@match/unset'; | ||
}; | ||
declare type NonExhaustivePattern<i> = { | ||
__nonExhaustive: never; | ||
} & i; | ||
/** | ||
* ### ExhaustiveMatch | ||
* An interface to create an exhaustive pattern matching clause. | ||
*/ | ||
export declare type ExhaustiveMatch<i, o> = { | ||
/** | ||
* ### Match.with | ||
* If the data matches the pattern provided as first argument, | ||
* use this branch and execute the handler function. | ||
**/ | ||
with<p extends ExhaustivePattern<i>, c>(pattern: p, handler: (value: MatchedValue<i, p>, selections: ExtractSelections<i, p>) => PickReturnValue<o, c>): ExhaustiveMatch<Exclude<i, ExtractPreciseValue<i, InvertPattern<p>>>, PickReturnValue<o, c>>; | ||
/** | ||
* ### Match.otherwise | ||
* takes a function returning the default value | ||
* and return the matched result. | ||
* | ||
* Equivalent to `.with(__, () => x).run()` | ||
**/ | ||
otherwise: <c>(handler: () => PickReturnValue<o, c>) => PickReturnValue<o, c>; | ||
/** | ||
* ### Match.run | ||
* Runs the pattern matching and return a value. | ||
* | ||
* If this is of type `NonExhaustivePattern`, it means you aren't matching | ||
* every cases, and you should probably add a another `.with(...)` clause | ||
* to prevent potential runtime errors. | ||
* */ | ||
run: [i] extends [never] ? () => o : NonExhaustivePattern<i>; | ||
}; | ||
export {}; |
@@ -1,9 +0,2 @@ | ||
export declare enum PatternType { | ||
String = "@match/string", | ||
Number = "@match/number", | ||
Boolean = "@match/boolean", | ||
Guard = "@match/guard", | ||
Not = "@match/not", | ||
Select = "@match/select" | ||
} | ||
import type { __, PatternType } from '../PatternType'; | ||
export declare type Primitives = number | boolean | string | undefined | null | symbol | bigint; | ||
@@ -27,3 +20,3 @@ /** | ||
}; | ||
declare type SpecialPattern<a> = a extends number ? typeof __.number | typeof __ : a extends string ? typeof __.string | typeof __ : a extends boolean ? typeof __.boolean | typeof __ : typeof __; | ||
declare type WildCardPattern<a> = a extends number ? typeof __.number | typeof __ : a extends string ? typeof __.string | typeof __ : a extends boolean ? typeof __.boolean | typeof __ : typeof __; | ||
/** | ||
@@ -34,29 +27,34 @@ * ### Pattern | ||
*/ | ||
export declare type Pattern<a> = SelectPattern<string> | GuardPattern<a> | NotPattern<a | any> | SpecialPattern<a> | (a extends Primitives ? a : a extends [infer b, infer c, infer d, infer e, infer f] ? [Pattern<b>, Pattern<c>, Pattern<d>, Pattern<e>, Pattern<f>] : a extends [infer b, infer c, infer d, infer e] ? [Pattern<b>, Pattern<c>, Pattern<d>, Pattern<e>] : a extends [infer b, infer c, infer d] ? [Pattern<b>, Pattern<c>, Pattern<d>] : a extends [infer b, infer c] ? [Pattern<b>, Pattern<c>] : a extends (infer b)[] ? [] | [Pattern<b>] | [Pattern<b>, Pattern<b>] | [Pattern<b>, Pattern<b>, Pattern<b>] | [Pattern<b>, Pattern<b>, Pattern<b>, Pattern<b>] | [Pattern<b>, Pattern<b>, Pattern<b>, Pattern<b>, Pattern<b>] : a extends Map<infer k, infer v> ? Map<k, Pattern<v>> : a extends Set<infer v> ? Set<Pattern<v>> : a extends object ? { | ||
export declare type Pattern<a> = SelectPattern<string> | GuardPattern<a> | NotPattern<a | any> | WildCardPattern<a> | (a extends Primitives ? a : a extends [infer b, infer c, infer d, infer e, infer f] ? [Pattern<b>, Pattern<c>, Pattern<d>, Pattern<e>, Pattern<f>] : a extends [infer b, infer c, infer d, infer e] ? [Pattern<b>, Pattern<c>, Pattern<d>, Pattern<e>] : a extends [infer b, infer c, infer d] ? [Pattern<b>, Pattern<c>, Pattern<d>] : a extends [infer b, infer c] ? [Pattern<b>, Pattern<c>] : a extends (infer b)[] ? [] | [Pattern<b>] | [Pattern<b>, Pattern<b>] | [Pattern<b>, Pattern<b>, Pattern<b>] | [Pattern<b>, Pattern<b>, Pattern<b>, Pattern<b>] | [Pattern<b>, Pattern<b>, Pattern<b>, Pattern<b>, Pattern<b>] : a extends Map<infer k, infer v> ? Map<k, Pattern<v>> : a extends Set<infer v> ? Set<Pattern<v>> : a extends object ? { | ||
[k in keyof a]?: Pattern<a[k]>; | ||
} : a); | ||
export declare const when: <a, b extends a = a>(predicate: GuardFunction<a, b>) => GuardPattern<a, b>; | ||
export declare const not: <a>(pattern: Pattern<a>) => NotPattern<a>; | ||
export declare const select: <k extends string>(key: k) => SelectPattern<k>; | ||
/** | ||
* ### Catch All wildcard | ||
* `__` 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') | ||
* ### ExhaustivePattern | ||
* Just like the Pattern type, excluding when clauses. | ||
*/ | ||
export declare const __: { | ||
readonly string: PatternType.String; | ||
readonly number: PatternType.Number; | ||
readonly boolean: PatternType.Boolean; | ||
}; | ||
export declare type ExhaustivePattern<a> = SelectPattern<string> | NotPattern<a | any> | WildCardPattern<a> | (a extends Primitives ? a : a extends [infer b, infer c, infer d, infer e, infer f] ? [ | ||
ExhaustivePattern<b>, | ||
ExhaustivePattern<c>, | ||
ExhaustivePattern<d>, | ||
ExhaustivePattern<e>, | ||
ExhaustivePattern<f> | ||
] : a extends [infer b, infer c, infer d, infer e] ? [ | ||
ExhaustivePattern<b>, | ||
ExhaustivePattern<c>, | ||
ExhaustivePattern<d>, | ||
ExhaustivePattern<e> | ||
] : a extends [infer b, infer c, infer d] ? [ExhaustivePattern<b>, ExhaustivePattern<c>, ExhaustivePattern<d>] : a extends [infer b, infer c] ? [ExhaustivePattern<b>, ExhaustivePattern<c>] : a extends (infer b)[] ? [] | [ExhaustivePattern<b>] | [ExhaustivePattern<b>, ExhaustivePattern<b>] | [ExhaustivePattern<b>, ExhaustivePattern<b>, ExhaustivePattern<b>] | [ | ||
ExhaustivePattern<b>, | ||
ExhaustivePattern<b>, | ||
ExhaustivePattern<b>, | ||
ExhaustivePattern<b> | ||
] | [ | ||
ExhaustivePattern<b>, | ||
ExhaustivePattern<b>, | ||
ExhaustivePattern<b>, | ||
ExhaustivePattern<b>, | ||
ExhaustivePattern<b> | ||
] : a extends Map<infer k, infer v> ? Map<k, ExhaustivePattern<v>> : a extends Set<infer v> ? Set<ExhaustivePattern<v>> : a extends object ? { | ||
[k in keyof a]?: ExhaustivePattern<a[k]>; | ||
} : a); | ||
export {}; |
"use strict"; | ||
exports.__esModule = true; | ||
exports.__ = exports.select = exports.not = exports.when = exports.PatternType = void 0; | ||
var PatternType; | ||
(function (PatternType) { | ||
PatternType["String"] = "@match/string"; | ||
PatternType["Number"] = "@match/number"; | ||
PatternType["Boolean"] = "@match/boolean"; | ||
PatternType["Guard"] = "@match/guard"; | ||
PatternType["Not"] = "@match/not"; | ||
PatternType["Select"] = "@match/select"; | ||
})(PatternType = exports.PatternType || (exports.PatternType = {})); | ||
exports.when = function (predicate) { return ({ | ||
__patternKind: PatternType.Guard, | ||
__when: predicate | ||
}); }; | ||
exports.not = function (pattern) { return ({ | ||
__patternKind: PatternType.Not, | ||
__pattern: pattern | ||
}); }; | ||
exports.select = function (key) { return ({ | ||
__patternKind: PatternType.Select, | ||
__key: key | ||
}); }; | ||
/** | ||
* ### Catch All wildcard | ||
* `__` 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') | ||
*/ | ||
exports.__ = { | ||
string: PatternType.String, | ||
number: PatternType.Number, | ||
boolean: PatternType.Boolean | ||
}; |
{ | ||
"name": "ts-pattern", | ||
"version": "1.1.0", | ||
"version": "2.0.1-next.0", | ||
"description": "Typescript pattern matching library", | ||
@@ -8,5 +8,4 @@ "main": "lib/index.js", | ||
"scripts": { | ||
"clean": "rimraf lib", | ||
"build": "tsc -d", | ||
"prepare": "npm run test && npm run clean && npm run build", | ||
"build": "rimraf lib && tsc -d", | ||
"prepare": "npm run test && npm run build", | ||
"test:values": "jest", | ||
@@ -40,9 +39,9 @@ "test:types": "tsc --project tests/tsconfig.json", | ||
"devDependencies": { | ||
"@types/jest": "^25.2.3", | ||
"jest": "^26.0.1", | ||
"@types/jest": "^26.0.15", | ||
"jest": "^26.6.3", | ||
"prettier": "^2.0.5", | ||
"rimraf": "^3.0.2", | ||
"ts-jest": "^26.0.0", | ||
"typescript": "^3.9.3" | ||
"ts-jest": "^26.4.4", | ||
"typescript": "^4.1.2" | ||
} | ||
} |
@@ -40,3 +40,3 @@ <h1 align="center">ts-pattern</h1> | ||
- Supports catch all (`__`) and type specific **wildcards**. | ||
- Supports `when(<predicate>)` and `not(<pattern>)` patterns for complexe cases. | ||
- Supports `when(<predicate>)` and `not(<pattern>)` patterns for complex cases. | ||
- Supports properties selection, via the `select(<name>)` function. | ||
@@ -49,3 +49,3 @@ - Tiny bundle footprint (**only 1kb**). | ||
Pattern Matching is implemented in Elixir, Rust, Haskell, Swift 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 (if ever). Lukily, 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 Elixir, Rust, Haskell, Swift 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 (if ever). Luckily, pattern matching can be implemented in userland. `ts-pattern` Provides a typesafe pattern matching implementation that you can start using today. | ||
@@ -69,3 +69,3 @@ ## Installation | ||
- [Code Sandbox Examples](#code-sandbox-examples) | ||
- [Intro to key concepts](#intro-to-key-concepts) | ||
- [Getting Started](#getting-started) | ||
- [API Reference](#api-reference) | ||
@@ -102,16 +102,17 @@ - [match](#match) | ||
## Intro to key concepts | ||
## Getting Started | ||
Sometimes you want to match on two values at once. Let's say we want to | ||
create a reducer function, we could make a switch on the event's type, but | ||
generally an event only makes sense if we are in a certain state. | ||
As an example, we are going to create a state reducer for a | ||
frontend application fetching some data using an HTTP request. | ||
To avoid unwanted state changes that could lead to bugs, **we pattern match | ||
on both the state and the event** and return a new state. | ||
### 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. | ||
### Example: a state reducer with match | ||
```ts | ||
@@ -131,2 +132,12 @@ type State = | ||
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 to create | ||
a reducer function that **matches on both the state and the event** | ||
and return a new state. | ||
This is a case were `match` really shines. Instead of writing nested | ||
switch statements, we can do that in a very expressive way: | ||
```ts | ||
@@ -191,3 +202,3 @@ import { match, __, not, select, when } from 'ts-pattern'; | ||
and output with `match<Input, Output>(...)` because `match` is able to | ||
infer both of this values. | ||
infer both of these types. | ||
@@ -304,3 +315,3 @@ ### .with(pattern, handler) | ||
### .match | ||
### match | ||
@@ -440,3 +451,3 @@ ```ts | ||
Literals are primitive javascript values, like number, string, boolean, bigint, null, undefined, and symbol. | ||
Literals are primitive JavaScript values, like number, string, boolean, bigint, null, undefined, and symbol. | ||
@@ -757,5 +768,5 @@ ```ts | ||
`ts-pattern` strongly invests on typescript's type inference to narrow | ||
the type of your value to something that match what you would expect. | ||
Here are a few example: | ||
`ts-pattern` strongly invests on TypeScript's type inference to narrow | ||
the type of your value to something that matches what you would expect. | ||
Here are a few examples: | ||
@@ -783,3 +794,3 @@ ```ts | ||
.with({ type: when(() => true) }, (value) => 'ok') // value: { type: string } | ||
.with({ type: not('hello' as 'hello') }, (value) => 'ok') // value: { type: string } | ||
.with({ type: not('hello' as const) }, (value) => 'ok') // value: { type: string } | ||
.with({ type: not(__.string) }, (value) => 'ok') // value: never | ||
@@ -794,3 +805,3 @@ .with({ type: not(when(() => true)) }, (value) => 'ok') // value: { type: string } | ||
[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 realise pattern matching could be implemented in userland and we didn't have | ||
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 🙏 | ||
@@ -797,0 +808,0 @@ |
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
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
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
53744
20
662
808
1