ts-pattern
Advanced tools
Comparing version 3.2.1-next.0 to 3.2.1-next.1
@@ -1,14 +0,10 @@ | ||
import type { Pattern, AnonymousSelectPattern, NamedSelectPattern, GuardPattern, NotPattern, GuardFunction } from './types/Pattern'; | ||
import type { Match } from './types/Match'; | ||
import { __ } from './PatternType'; | ||
import { AnyConstructor } from './types/helpers'; | ||
export declare const when: <a, b extends a = never>(predicate: GuardFunction<a, b>) => GuardPattern<a, b>; | ||
export declare const not: <a>(pattern: Pattern<a>) => NotPattern<a>; | ||
export declare function select(): AnonymousSelectPattern; | ||
export declare function select<k extends string>(key: k): NamedSelectPattern<k>; | ||
export declare function instanceOf<T extends AnyConstructor>(classConstructor: T): GuardPattern<unknown, InstanceType<T>>; | ||
import type { Pattern } from './types/Pattern'; | ||
import type { Match, MatchedValue } from './types/Match'; | ||
import { when, not, select, instanceOf } from './guards'; | ||
import { __ } from './wildcards'; | ||
import { InvertPattern } from './types/InvertPattern'; | ||
/** | ||
* # Pattern matching | ||
**/ | ||
export { Pattern, __ }; | ||
export { Pattern, __, when, not, select, instanceOf }; | ||
/** | ||
@@ -23,1 +19,18 @@ * #### match | ||
export declare const match: <a, b = "@ts-pattern/unset">(value: a) => Match<a, b, never, never>; | ||
/** | ||
* Helper function taking a pattern and returning a **type guard** function telling | ||
* us whether or not a value matches the pattern. | ||
* | ||
* @param pattern the Pattern the value should match | ||
* @returns a function taking the value and returning whether or not it matches the pattern. | ||
*/ | ||
export declare function isMatching<p extends Pattern<any>>(pattern: p): (value: any) => value is MatchedValue<any, InvertPattern<p>>; | ||
/** | ||
* **type guard** function taking a pattern and a value and returning a boolean telling | ||
* us whether or not the value matches the pattern. | ||
* | ||
* @param pattern the Pattern the value should match | ||
* @param value | ||
* @returns a boolean telling whether or not the value matches the pattern. | ||
*/ | ||
export declare function isMatching<p extends Pattern<any>>(pattern: p, value: any): value is MatchedValue<any, InvertPattern<p>>; |
378
lib/index.js
"use strict"; | ||
var __read = (this && this.__read) || function (o, n) { | ||
var m = typeof Symbol === "function" && o[Symbol.iterator]; | ||
if (!m) return o; | ||
var i = m.call(o), r, ar = [], e; | ||
try { | ||
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); | ||
} | ||
catch (error) { e = { error: error }; } | ||
finally { | ||
try { | ||
if (r && !r.done && (m = i["return"])) m.call(i); | ||
} | ||
finally { if (e) throw e.error; } | ||
} | ||
return ar; | ||
}; | ||
var __spreadArray = (this && this.__spreadArray) || function (to, from) { | ||
for (var i = 0, il = from.length, j = to.length; i < il; i++, j++) | ||
to[j] = from[i]; | ||
return to; | ||
}; | ||
exports.__esModule = true; | ||
exports.match = exports.__ = exports.instanceOf = exports.select = exports.not = exports.when = void 0; | ||
var PatternType_1 = require("./PatternType"); | ||
exports.__ = PatternType_1.__; | ||
var when = function (predicate) { return ({ | ||
'@ts-pattern/__patternKind': PatternType_1.PatternType.Guard, | ||
'@ts-pattern/__when': predicate | ||
}); }; | ||
exports.when = when; | ||
var not = function (pattern) { return ({ | ||
'@ts-pattern/__patternKind': PatternType_1.PatternType.Not, | ||
'@ts-pattern/__pattern': pattern | ||
}); }; | ||
exports.not = not; | ||
function select(key) { | ||
return key === undefined | ||
? { | ||
'@ts-pattern/__patternKind': PatternType_1.PatternType.AnonymousSelect | ||
} | ||
: { | ||
'@ts-pattern/__patternKind': PatternType_1.PatternType.NamedSelect, | ||
'@ts-pattern/__key': key | ||
}; | ||
} | ||
exports.select = select; | ||
function instanceOf(classConstructor) { | ||
return exports.when(function (val) { return val instanceof classConstructor; }); | ||
} | ||
exports.instanceOf = instanceOf; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.isMatching = exports.match = exports.instanceOf = exports.select = exports.not = exports.when = exports.__ = void 0; | ||
const symbols = require("./symbols"); | ||
const guards_1 = require("./guards"); | ||
Object.defineProperty(exports, "when", { enumerable: true, get: function () { return guards_1.when; } }); | ||
Object.defineProperty(exports, "not", { enumerable: true, get: function () { return guards_1.not; } }); | ||
Object.defineProperty(exports, "select", { enumerable: true, get: function () { return guards_1.select; } }); | ||
Object.defineProperty(exports, "instanceOf", { enumerable: true, get: function () { return guards_1.instanceOf; } }); | ||
const wildcards_1 = require("./wildcards"); | ||
Object.defineProperty(exports, "__", { enumerable: true, get: function () { return wildcards_1.__; } }); | ||
/** | ||
@@ -60,5 +20,3 @@ * #### match | ||
*/ | ||
var match = function (value) { | ||
return builder(value, []); | ||
}; | ||
const match = (value) => builder(value, []); | ||
exports.match = match; | ||
@@ -69,13 +27,8 @@ /** | ||
* builder pattern. | ||
* This builder pattern is neat because we can have complexe type checking | ||
* for each of the methods adding new behavior to our pattern matching. | ||
*/ | ||
var builder = function (value, cases) { | ||
var run = function () { | ||
var entry = cases.find(function (_a) { | ||
var test = _a.test; | ||
return test(value); | ||
}); | ||
const builder = (value, cases) => { | ||
const run = () => { | ||
const entry = cases.find(({ test }) => test(value)); | ||
if (!entry) { | ||
var displayedValue = void 0; | ||
let displayedValue; | ||
try { | ||
@@ -87,3 +40,3 @@ displayedValue = JSON.stringify(value); | ||
} | ||
throw new Error("Pattern matching error: no pattern matches value " + displayedValue); | ||
throw new Error(`Pattern matching error: no pattern matches value ${displayedValue}`); | ||
} | ||
@@ -93,207 +46,140 @@ return entry.handler(entry.select(value), value); | ||
return { | ||
"with": function () { | ||
var args = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
args[_i] = arguments[_i]; | ||
} | ||
var _a = args.slice(0, -1).reduce(function (acc, arg) { | ||
with(...args) { | ||
const handler = args[args.length - 1]; | ||
const patterns = []; | ||
const predicates = []; | ||
for (let i = 0; i < args.length - 1; i++) { | ||
const arg = args[i]; | ||
if (typeof arg === 'function') { | ||
acc.predicates.push(arg); | ||
predicates.push(arg); | ||
} | ||
else { | ||
acc.patterns.push(arg); | ||
patterns.push(arg); | ||
} | ||
return acc; | ||
}, { patterns: [], predicates: [] }), patterns = _a.patterns, predicates = _a.predicates; | ||
var handler = args[args.length - 1]; | ||
var doesMatch = function (value) { | ||
return Boolean(patterns.some(function (pattern) { return matchPattern(pattern, value); }) && | ||
predicates.every(function (predicate) { return predicate(value); })); | ||
}; | ||
} | ||
let selected = {}; | ||
const doesMatch = (value) => Boolean(patterns.some((pattern) => matchPattern(pattern, value, (key, value) => { | ||
selected[key] = value; | ||
})) && predicates.every((predicate) => predicate(value))); | ||
return builder(value, cases.concat([ | ||
{ | ||
test: doesMatch, | ||
handler: handler, | ||
select: function (value) { | ||
return patterns.length === 1 | ||
? selectWithPattern(patterns[0], value) | ||
: value; | ||
} | ||
handler, | ||
select: (value) => Object.keys(selected).length | ||
? selected[guards_1.ANONYMOUS_SELECT_KEY] !== undefined | ||
? selected[guards_1.ANONYMOUS_SELECT_KEY] | ||
: selected | ||
: value, | ||
}, | ||
])); | ||
}, | ||
when: function (predicate, handler) { | ||
return builder(value, cases.concat([ | ||
{ | ||
test: predicate, | ||
handler: handler, | ||
select: function (value) { return value; } | ||
}, | ||
])); | ||
}, | ||
otherwise: function (handler) { | ||
return builder(value, cases.concat([ | ||
{ | ||
test: function (value) { return true; }, | ||
handler: handler, | ||
select: function (value) { return value; } | ||
}, | ||
])).exhaustive(); | ||
}, | ||
exhaustive: function () { return run(); }, | ||
run: run | ||
when: (predicate, handler) => builder(value, cases.concat([ | ||
{ | ||
test: predicate, | ||
handler, | ||
select: (value) => value, | ||
}, | ||
])), | ||
otherwise: (handler) => builder(value, cases.concat([ | ||
{ | ||
test: () => true, | ||
handler, | ||
select: (value) => value, | ||
}, | ||
])).run(), | ||
exhaustive: () => run(), | ||
run, | ||
}; | ||
}; | ||
var isObject = function (value) { | ||
return Boolean(value && typeof value === 'object'); | ||
const isObject = (value) => Boolean(value && typeof value === 'object'); | ||
const isGuardPattern = (x) => { | ||
const pattern = x; | ||
return pattern && pattern[symbols.PatternKind] === symbols.Guard; | ||
}; | ||
var isArray = function (value) { return Array.isArray(value); }; | ||
var isGuardPattern = function (x) { | ||
var pattern = x; | ||
return (pattern && | ||
pattern['@ts-pattern/__patternKind'] === PatternType_1.PatternType.Guard && | ||
typeof pattern['@ts-pattern/__when'] === 'function'); | ||
const isNotPattern = (x) => { | ||
const pattern = x; | ||
return pattern && pattern[symbols.PatternKind] === symbols.Not; | ||
}; | ||
var isNotPattern = function (x) { | ||
var pattern = x; | ||
return pattern && pattern['@ts-pattern/__patternKind'] === PatternType_1.PatternType.Not; | ||
const isNamedSelectPattern = (x) => { | ||
const pattern = x; | ||
return pattern && pattern[symbols.PatternKind] === symbols.NamedSelect; | ||
}; | ||
var isNamedSelectPattern = function (x) { | ||
var pattern = x; | ||
return (pattern && pattern['@ts-pattern/__patternKind'] === PatternType_1.PatternType.NamedSelect); | ||
const isAnonymousSelectPattern = (x) => { | ||
const pattern = x; | ||
return pattern && pattern[symbols.PatternKind] === symbols.AnonymousSelect; | ||
}; | ||
var isAnonymousSelectPattern = function (x) { | ||
var pattern = x; | ||
return (pattern && | ||
pattern['@ts-pattern/__patternKind'] === PatternType_1.PatternType.AnonymousSelect); | ||
}; | ||
var isListPattern = function (x) { | ||
return Array.isArray(x) && x.length === 1; | ||
}; | ||
// tells us if the value matches a given pattern. | ||
var matchPattern = function (pattern, value) { | ||
if (pattern === PatternType_1.__ || | ||
isNamedSelectPattern(pattern) || | ||
isAnonymousSelectPattern(pattern)) | ||
return true; | ||
if (pattern === PatternType_1.__.string) | ||
return typeof value === 'string'; | ||
if (pattern === PatternType_1.__.boolean) | ||
return typeof value === 'boolean'; | ||
if (pattern === PatternType_1.__.number) { | ||
return typeof value === 'number' && !Number.isNaN(value); | ||
} | ||
if (isGuardPattern(pattern)) | ||
return Boolean(pattern['@ts-pattern/__when'](value)); | ||
if (isNotPattern(pattern)) | ||
return !matchPattern(pattern['@ts-pattern/__pattern'], value); | ||
if (isListPattern(pattern)) | ||
return isArray(value) | ||
? value.every(function (v) { return matchPattern(pattern[0], v); }) | ||
: false; | ||
if (typeof pattern !== typeof value) | ||
return false; | ||
if (isArray(pattern)) { | ||
return isArray(value) && pattern.length === value.length | ||
? pattern.every(function (subPattern, i) { return matchPattern(subPattern, value[i]); }) | ||
: false; | ||
} | ||
if (pattern instanceof Map) { | ||
if (!(value instanceof Map)) | ||
return false; | ||
return __spreadArray([], __read(pattern.keys())).every(function (key) { | ||
return matchPattern(pattern.get(key), value.get(key)); | ||
}); | ||
} | ||
if (pattern instanceof Set) { | ||
if (!(value instanceof Set)) | ||
return false; | ||
var patternValues = __spreadArray([], __read(pattern.values())); | ||
var allValues_1 = __spreadArray([], __read(value.values())); | ||
return patternValues.length === 0 | ||
? allValues_1.length === 0 | ||
: patternValues.length === 1 | ||
? patternValues.every(function (subPattern) { | ||
return Object.values(PatternType_1.__).includes(subPattern) | ||
? matchPattern([subPattern], allValues_1) | ||
: value.has(subPattern); | ||
}) | ||
: patternValues.every(function (subPattern) { return value.has(subPattern); }); | ||
} | ||
const matchPattern = (pattern, value, select) => { | ||
if (isObject(pattern)) { | ||
if (isGuardPattern(pattern)) | ||
return Boolean(pattern[symbols.Guard](value)); | ||
if (isNamedSelectPattern(pattern)) { | ||
select(pattern[symbols.NamedSelect], value); | ||
return true; | ||
} | ||
if (isAnonymousSelectPattern(pattern)) { | ||
select(guards_1.ANONYMOUS_SELECT_KEY, value); | ||
return true; | ||
} | ||
if (isNotPattern(pattern)) | ||
return !matchPattern(pattern[symbols.Not], value, select); | ||
if (!isObject(value)) | ||
return false; | ||
return Object.keys(pattern).every(function (k) { | ||
// @ts-ignore | ||
return matchPattern(pattern[k], value[k]); | ||
}); | ||
if (Array.isArray(pattern)) { | ||
if (!Array.isArray(value)) | ||
return false; | ||
// List pattern | ||
if (pattern.length === 1) { | ||
const selected = {}; | ||
const listSelect = (key, value) => { | ||
selected[key] = (selected[key] || []).concat([value]); | ||
}; | ||
const doesMatch = value.every((v) => matchPattern(pattern[0], v, listSelect)); | ||
if (doesMatch) { | ||
Object.keys(selected).forEach((key) => select(key, selected[key])); | ||
} | ||
return doesMatch; | ||
} | ||
// Tuple pattern | ||
return pattern.length === value.length | ||
? pattern.every((subPattern, i) => matchPattern(subPattern, value[i], select)) | ||
: false; | ||
} | ||
if (pattern instanceof Map) { | ||
if (!(value instanceof Map)) | ||
return false; | ||
return [...pattern.keys()].every((key) => matchPattern(pattern.get(key), value.get(key), select)); | ||
} | ||
if (pattern instanceof Set) { | ||
if (!(value instanceof Set)) | ||
return false; | ||
if (pattern.size === 0) | ||
return value.size === 0; | ||
if (pattern.size === 1) { | ||
const [subPattern] = [...pattern.values()]; | ||
return Object.values(wildcards_1.__).includes(subPattern) | ||
? matchPattern([subPattern], [...value.values()], select) | ||
: value.has(subPattern); | ||
} | ||
return [...pattern.values()].every((subPattern) => value.has(subPattern)); | ||
} | ||
return Object.keys(pattern).every((k) => matchPattern( | ||
// @ts-ignore | ||
pattern[k], | ||
// @ts-ignore | ||
value[k], select)); | ||
} | ||
return value === pattern; | ||
}; | ||
var selectWithPattern = function (pattern, value) { | ||
var positional = selectPositionalWithPattern(pattern, value); | ||
var kwargs = selectKwargsWithPattern(pattern, value); | ||
return positional.kind === 'some' | ||
? positional.value | ||
: Object.keys(kwargs).length | ||
? kwargs | ||
: value; | ||
}; | ||
var none = { kind: 'none' }; | ||
var selectPositionalWithPattern = function (pattern, value) { | ||
if (isAnonymousSelectPattern(pattern)) | ||
return { kind: 'some', value: value }; | ||
if (isListPattern(pattern) && isArray(value)) | ||
return value | ||
.map(function (v) { return selectPositionalWithPattern(pattern[0], v); }) | ||
.filter(function (selection) { | ||
return selection.kind === 'some'; | ||
}) | ||
.reduce(function (acc, selection) { | ||
return acc.kind === 'none' | ||
? { kind: 'some', value: [selection.value] } | ||
: { kind: 'some', value: acc.value.concat([selection.value]) }; | ||
}, none); | ||
if (isArray(pattern) && isArray(value)) | ||
return pattern.length <= value.length | ||
? pattern.reduce(function (acc, subPattern, i) { | ||
if (acc.kind === 'some') | ||
return acc; | ||
return selectPositionalWithPattern(subPattern, value[i]); | ||
}, none) | ||
: none; | ||
if (isObject(pattern) && isObject(value)) | ||
return Object.keys(pattern).reduce(function (acc, k) { | ||
if (acc.kind === 'some') | ||
return acc; | ||
// @ts-ignore | ||
return selectPositionalWithPattern(pattern[k], value[k]); | ||
}, none); | ||
return none; | ||
}; | ||
var selectKwargsWithPattern = function (pattern, value) { | ||
var _a; | ||
if (isNamedSelectPattern(pattern)) | ||
return _a = {}, _a[pattern['@ts-pattern/__key']] = value, _a; | ||
if (isListPattern(pattern) && isArray(value)) | ||
return value | ||
.map(function (v) { return selectKwargsWithPattern(pattern[0], v); }) | ||
.reduce(function (acc, selections) { | ||
return Object.keys(selections).reduce(function (acc, key) { | ||
acc[key] = (acc[key] || []).concat([selections[key]]); | ||
return acc; | ||
}, acc); | ||
}, {}); | ||
if (isArray(pattern) && isArray(value)) | ||
return pattern.length <= value.length | ||
? pattern.reduce(function (acc, subPattern, i) { | ||
return Object.assign(acc, selectKwargsWithPattern(subPattern, value[i])); | ||
}, {}) | ||
: {}; | ||
if (isObject(pattern) && isObject(value)) | ||
return Object.keys(pattern).reduce(function (acc, k) { | ||
// @ts-ignore | ||
return Object.assign(acc, selectKwargsWithPattern(pattern[k], value[k])); | ||
}, {}); | ||
return {}; | ||
}; | ||
function isMatching(...args) { | ||
if (args.length === 1) { | ||
const [pattern] = args; | ||
return (value) => matchPattern(pattern, value, () => { }); | ||
} | ||
if (args.length === 2) { | ||
const [pattern, value] = args; | ||
return matchPattern(pattern, value, () => { }); | ||
} | ||
throw new Error(`isMatching wasn't given enough arguments: expected 1 or 2, receive ${args.length}.`); | ||
} | ||
exports.isMatching = isMatching; |
"use strict"; | ||
exports.__esModule = true; | ||
Object.defineProperty(exports, "__esModule", { value: true }); |
"use strict"; | ||
exports.__esModule = true; | ||
Object.defineProperty(exports, "__esModule", { value: true }); |
"use strict"; | ||
exports.__esModule = true; | ||
Object.defineProperty(exports, "__esModule", { value: true }); |
"use strict"; | ||
exports.__esModule = true; | ||
Object.defineProperty(exports, "__esModule", { value: true }); |
@@ -1,2 +0,2 @@ | ||
import { PatternType } from '../PatternType'; | ||
import type * as symbols from '../symbols'; | ||
import type { Cast, IsPlainObject, UnionToIntersection } from './helpers'; | ||
@@ -7,3 +7,3 @@ import type { NamedSelectPattern, AnonymousSelectPattern } from './Pattern'; | ||
} : p extends AnonymousSelectPattern ? { | ||
[kk in PatternType.AnonymousSelect]: [i, path]; | ||
[kk in symbols.AnonymousSelect]: [i, path]; | ||
} : p extends readonly (infer pp)[] ? i extends readonly (infer ii)[] ? [i, p] extends [ | ||
@@ -38,5 +38,5 @@ readonly [infer i1, infer i2, infer i3, infer i4, infer i5], | ||
} & a; | ||
declare type SelectionToArgs<selections extends Record<string, [unknown, unknown]>, i> = [keyof selections] extends [never] ? i : PatternType.AnonymousSelect extends keyof selections ? [ | ||
selections[PatternType.AnonymousSelect][1] | ||
] extends [never] ? SeveralAnonymousSelectError : keyof selections extends PatternType.AnonymousSelect ? selections[PatternType.AnonymousSelect][0] : MixedNamedAndAnonymousSelectError : { | ||
declare type SelectionToArgs<selections extends Record<string, [unknown, unknown]>, i> = [keyof selections] extends [never] ? i : symbols.AnonymousSelect extends keyof selections ? [ | ||
selections[symbols.AnonymousSelect][1] | ||
] extends [never] ? SeveralAnonymousSelectError : keyof selections extends symbols.AnonymousSelect ? selections[symbols.AnonymousSelect][0] : MixedNamedAndAnonymousSelectError : { | ||
[k in keyof selections]: selections[k][0]; | ||
@@ -43,0 +43,0 @@ }; |
"use strict"; | ||
exports.__esModule = true; | ||
Object.defineProperty(exports, "__esModule", { value: true }); |
@@ -30,3 +30,3 @@ export declare type ValueOf<a> = a extends any[] ? a[number] : a[keyof a]; | ||
export declare type Expect<T extends true> = T; | ||
export declare type IsAny<a> = [a] extends [never] ? false : Equal<a, any>; | ||
export declare type IsAny<T> = 0 extends 1 & T ? true : false; | ||
export declare type Length<it extends any[]> = it['length']; | ||
@@ -41,3 +41,3 @@ export declare type Iterator<n extends number, it extends any[] = []> = it['length'] extends n ? it : Iterator<n, [any, ...it]>; | ||
}; | ||
export declare type IsPlainObject<o> = o extends object ? o extends BuiltInObjects ? false : true : false; | ||
export declare type IsPlainObject<o> = o extends object ? o extends string | BuiltInObjects ? false : true : false; | ||
export declare type Compute<a extends any> = a extends BuiltInObjects ? a : { | ||
@@ -52,3 +52,2 @@ [k in keyof a]: a[k]; | ||
export declare type Union<a, b> = [b] extends [a] ? a : [a] extends [b] ? b : a | b; | ||
export declare type AnyConstructor = new (...args: any[]) => any; | ||
export {}; |
"use strict"; | ||
exports.__esModule = true; | ||
Object.defineProperty(exports, "__esModule", { value: true }); |
@@ -1,2 +0,1 @@ | ||
import type { __ } from '../PatternType'; | ||
import { IsPlainObject, Primitives, IsLiteral } from './helpers'; | ||
@@ -9,3 +8,3 @@ import type { NamedSelectPattern, AnonymousSelectPattern, GuardPattern, NotPattern } from './Pattern'; | ||
*/ | ||
export declare type InvertPattern<p> = p extends typeof __.number ? number : p extends typeof __.string ? string : p extends typeof __.boolean ? boolean : p extends NamedSelectPattern<any> | AnonymousSelectPattern | typeof __ ? unknown : p extends GuardPattern<infer p1, infer p2> ? [p2] extends [never] ? p1 : p2 : p extends NotPattern<infer a1> ? NotPattern<InvertPattern<a1>> : p extends Primitives ? p : p extends readonly (infer pp)[] ? p extends readonly [infer p1, infer p2, infer p3, infer p4, infer p5] ? [ | ||
export declare type InvertPattern<p> = p extends NamedSelectPattern<any> | AnonymousSelectPattern ? unknown : p extends GuardPattern<infer p1, infer p2> ? [p2] extends [never] ? p1 : p2 : p extends NotPattern<infer a1> ? NotPattern<InvertPattern<a1>> : p extends Primitives ? p : p extends readonly (infer pp)[] ? p extends readonly [infer p1, infer p2, infer p3, infer p4, infer p5] ? [ | ||
InvertPattern<p1>, | ||
@@ -27,3 +26,3 @@ InvertPattern<p2>, | ||
*/ | ||
export declare type InvertPatternForExclude<p, i> = p extends NotPattern<infer p1> ? Exclude<i, p1> : p extends typeof __.number ? number : p extends typeof __.string ? string : p extends typeof __.boolean ? boolean : p extends NamedSelectPattern<any> | AnonymousSelectPattern | typeof __ ? unknown : p extends GuardPattern<any, infer p1> ? p1 : p extends Primitives ? IsLiteral<p> extends true ? p : IsLiteral<i> extends true ? p : never : p extends readonly (infer pp)[] ? i extends readonly (infer ii)[] ? p extends readonly [infer p1, infer p2, infer p3, infer p4, infer p5] ? i extends readonly [infer i1, infer i2, infer i3, infer i4, infer i5] ? [ | ||
export declare type InvertPatternForExclude<p, i> = p extends NotPattern<infer p1> ? Exclude<i, p1> : p extends NamedSelectPattern<any> | AnonymousSelectPattern ? unknown : p extends GuardPattern<any, infer p1> ? p1 : p extends Primitives ? IsLiteral<p> extends true ? p : IsLiteral<i> extends true ? p : never : p extends readonly (infer pp)[] ? i extends readonly (infer ii)[] ? p extends readonly [infer p1, infer p2, infer p3, infer p4, infer p5] ? i extends readonly [infer i1, infer i2, infer i3, infer i4, infer i5] ? [ | ||
InvertPatternForExclude<p1, i1>, | ||
@@ -30,0 +29,0 @@ InvertPatternForExclude<p2, i2>, |
"use strict"; | ||
exports.__esModule = true; | ||
Object.defineProperty(exports, "__esModule", { value: true }); |
"use strict"; | ||
exports.__esModule = true; | ||
Object.defineProperty(exports, "__esModule", { value: true }); |
"use strict"; | ||
exports.__esModule = true; | ||
Object.defineProperty(exports, "__esModule", { value: true }); |
@@ -1,2 +0,2 @@ | ||
import type { __, PatternType } from '../PatternType'; | ||
import type * as symbols from '../symbols'; | ||
import { Primitives, IsPlainObject } from './helpers'; | ||
@@ -8,29 +8,24 @@ /** | ||
export declare type GuardFunction<a, b extends a> = ((value: a) => value is b) | ((value: a) => boolean); | ||
/** | ||
* Using @deprecated here to dissuade people from using them inside there patterns. | ||
* Theses properties should be used by ts-pattern's internals only. | ||
*/ | ||
export declare type GuardPattern<a, b extends a = never> = { | ||
/** @deprecated This property should only be used by ts-pattern's internals. */ | ||
'@ts-pattern/__patternKind': PatternType.Guard; | ||
/** @deprecated This property should only be used by ts-pattern's internals. */ | ||
'@ts-pattern/__when': GuardFunction<a, b>; | ||
/** @internal This property should only be used by ts-pattern's internals. */ | ||
[symbols.PatternKind]: symbols.Guard; | ||
/** @internal This property should only be used by ts-pattern's internals. */ | ||
[symbols.Guard]: GuardFunction<a, b>; | ||
}; | ||
export declare type NotPattern<a> = { | ||
/** @deprecated This property should only be used by ts-pattern's internals. */ | ||
'@ts-pattern/__patternKind': PatternType.Not; | ||
/** @deprecated This property should only be used by ts-pattern's internals. */ | ||
'@ts-pattern/__pattern': Pattern<a>; | ||
/** @internal This property should only be used by ts-pattern's internals. */ | ||
[symbols.PatternKind]: symbols.Not; | ||
/** @internal This property should only be used by ts-pattern's internals. */ | ||
[symbols.Not]: Pattern<a>; | ||
}; | ||
export declare type AnonymousSelectPattern = { | ||
/** @deprecated This property should only be used by ts-pattern's internals. */ | ||
'@ts-pattern/__patternKind': PatternType.AnonymousSelect; | ||
/** @internal This property should only be used by ts-pattern's internals. */ | ||
[symbols.PatternKind]: symbols.AnonymousSelect; | ||
}; | ||
export declare type NamedSelectPattern<k extends string> = { | ||
/** @deprecated This property should only be used by ts-pattern's internals. */ | ||
'@ts-pattern/__patternKind': PatternType.NamedSelect; | ||
/** @deprecated This property should only be used by ts-pattern's internals. */ | ||
'@ts-pattern/__key': k; | ||
/** @internal This property should only be used by ts-pattern's internals. */ | ||
[symbols.PatternKind]: symbols.NamedSelect; | ||
/** @internal This property should only be used by ts-pattern's internals. */ | ||
[symbols.NamedSelect]: k; | ||
}; | ||
declare type WildCardPattern<a> = a extends number ? typeof __.number : a extends string ? typeof __.string : a extends boolean ? typeof __.boolean : never; | ||
/** | ||
@@ -41,3 +36,3 @@ * ### Pattern | ||
*/ | ||
export declare type Pattern<a> = typeof __ | AnonymousSelectPattern | NamedSelectPattern<string> | GuardPattern<a, a> | NotPattern<a | any> | WildCardPattern<a> | (a extends Primitives ? a : a extends readonly (infer i)[] ? a extends readonly [infer a1, infer a2, infer a3, infer a4, infer a5] ? readonly [ | ||
export declare type Pattern<a> = AnonymousSelectPattern | NamedSelectPattern<string> | GuardPattern<a, a> | NotPattern<a | any> | (a extends Primitives ? a : a extends readonly (infer i)[] ? a extends readonly [infer a1, infer a2, infer a3, infer a4, infer a5] ? readonly [ | ||
Pattern<a1>, | ||
@@ -57,2 +52,1 @@ Pattern<a2>, | ||
} : a); | ||
export {}; |
"use strict"; | ||
exports.__esModule = true; | ||
Object.defineProperty(exports, "__esModule", { value: true }); |
{ | ||
"name": "ts-pattern", | ||
"version": "3.2.1-next.0", | ||
"version": "3.2.1-next.1", | ||
"description": "Typescript pattern matching library", | ||
@@ -8,3 +8,3 @@ "main": "lib/index.js", | ||
"scripts": { | ||
"build": "rimraf lib && tsc -d", | ||
"build": "rimraf lib && tsc", | ||
"prepare": "npm run test && npm run build", | ||
@@ -40,9 +40,9 @@ "test:values": "jest", | ||
"devDependencies": { | ||
"@types/jest": "^26.0.15", | ||
"jest": "^26.6.3", | ||
"@types/jest": "^26.0.23", | ||
"jest": "^27.0.3", | ||
"prettier": "^2.2.1", | ||
"rimraf": "^3.0.2", | ||
"ts-jest": "^26.4.4", | ||
"typescript": "^4.2.4" | ||
"ts-jest": "^27.0.1", | ||
"typescript": "^4.3.2" | ||
} | ||
} |
127
README.md
@@ -88,3 +88,5 @@ <h1 align="center">ts-pattern</h1> | ||
- [.when](#when) | ||
- [.otherwise](#when) | ||
- [.otherwise](#otherwise) | ||
- [.run](#run) | ||
- [isMatching](#ismatching) | ||
- [Patterns](#patterns) | ||
@@ -96,2 +98,3 @@ - [Literals](#literals) | ||
- [`__.boolean` wildcard](#__boolean-wildcard) | ||
- [`__.nullish` wildcard](#__nullish-wildcard) | ||
- [Objects](#objects) | ||
@@ -105,2 +108,3 @@ - [Lists (arrays)](#lists-arrays) | ||
- [`select` patterns](#select-patterns) | ||
- [`instanceOf` patterns](#instanceof-patterns) | ||
- [Type inference](#type-inference) | ||
@@ -421,3 +425,3 @@ - [Inspirations](#inspirations) | ||
#### Options | ||
#### Arguments | ||
@@ -462,3 +466,3 @@ - `input` | ||
#### Options | ||
#### Arguments | ||
@@ -498,3 +502,3 @@ - `pattern: Pattern<TInput>` | ||
#### Options | ||
#### Arguments | ||
@@ -541,3 +545,3 @@ - `predicate: (value: TInput) => unknown` | ||
#### Options | ||
#### Arguments | ||
@@ -566,2 +570,56 @@ - `defaultHandler: () => TOutput` | ||
### `isMatching` | ||
With a single argument: | ||
```ts | ||
import { isMatching, __ } from 'ts-pattern'; | ||
const isBlogPost = isMatching({ | ||
title: __.string, | ||
description: __.string, | ||
}); | ||
if (isBlogPost(value)) { | ||
// value: { title: string, description: string } | ||
} | ||
``` | ||
With two arguments: | ||
```ts | ||
const blogPostPattern = { | ||
title: __.string, | ||
description: __.string, | ||
}; | ||
if (isMatching(blogPostPattern, value)) { | ||
// value: { title: string, description: string } | ||
} | ||
``` | ||
Type guard function to check if a value is matching a pattern or not. | ||
#### 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 or not the value matches the pattern. | ||
- if the only argument given to the function is the pattern, then `isMatching` will return a **type guard function** taking a value and returning a boolean telling us whether or not the value matches the pattern. | ||
### Patterns | ||
@@ -671,2 +729,29 @@ | ||
#### `__.nullish` wildcard | ||
The `__.nullish` pattern will match any value of type `null` or `undefined`. | ||
You will **not often need this wildcard** as ordinarily `null` and `undefined` | ||
are their own wildcards. | ||
However, sometimes `null` and `undefined` appear in a union together | ||
(e.g. `null | undefined | string`) and you may want to treat them as equivalent. | ||
This is often not the case in many contexts. However, if they do appear together | ||
in a union and you do want to treat them as equivalent then this may come in handy. | ||
```ts | ||
import { match, __ } from 'ts-pattern'; | ||
const input = null; | ||
const output = match<number | string | boolean | null | undefined>(input) | ||
.with(__.string, () => 'it is a string!') | ||
.with(__.number, () => 'it is a number!') | ||
.with(__.boolean, () => 'it is a boolean!') | ||
.with(__.nullish, () => 'it is either null or undefined!') | ||
.with(null, () => 'it is null!') | ||
.with(undefined, () => 'it is undefined!') | ||
.run(); | ||
console.log(output); | ||
// => 'it is either null or undefined!' | ||
``` | ||
#### Objects | ||
@@ -919,2 +1004,34 @@ | ||
#### `instanceOf` patterns | ||
The `instanceOf` function lets you build a pattern to check if | ||
a value is an instance of a class: | ||
```ts | ||
import { match, instanceOf } from 'ts-pattern'; | ||
class A { | ||
a = 'a'; | ||
} | ||
class B { | ||
b = 'b'; | ||
} | ||
type Input = { value: A | B }; | ||
const input = { value: new A() }; | ||
const output = match<Input>(input) | ||
.with({ value: instanceOf(A) }, (a) => { | ||
return 'instance of A!'; | ||
}) | ||
.with({ value: instanceOf(B) }, (b) => { | ||
return 'instance of B!'; | ||
}) | ||
.exhaustive(); | ||
console.log(output); | ||
// => 'instance of A!' | ||
``` | ||
### type inference | ||
@@ -921,0 +1038,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
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
75406
30
1076
850