From 0b92728a855afa8bca4b3683ee9786a050479666 Mon Sep 17 00:00:00 2001 From: gvergnaud Date: Tue, 9 May 2023 22:18:53 +0200 Subject: [PATCH] matcher: simplify matcher protocol and mark unstable --- src/patterns.ts | 55 ++++++++++++++++++++++++++-------- src/types/InvertPattern.ts | 12 ++++---- src/types/Pattern.ts | 4 +-- tests/matcher-protocol.test.ts | 21 ++++++------- 4 files changed, 60 insertions(+), 32 deletions(-) diff --git a/src/patterns.ts b/src/patterns.ts index 91bdd052..1c282abf 100644 --- a/src/patterns.ts +++ b/src/patterns.ts @@ -21,10 +21,51 @@ import { CustomP, } from './types/Pattern'; -export { Pattern }; +export { Pattern, Fn as unstable_Fn }; export { matcher }; +/** + * @experimental + * A `Matchable` is an object implementing + * the Matcher Protocol. It must have a `[P.matcher]: P.Matcher` + * key, which defines how this object should be matched by TS-Pattern. + * + * Note that this api is unstable. + * + * @example + * ```ts + * class Some implements P.unstable_Matchable { + * [P.matcher](): P.unstable_Matcher> + * } + * ``` + */ +export type unstable_Matchable< + narrowedOrFn, + input = unknown, + pattern = never +> = CustomP; + +/** + * @experimental + * A `Matcher` is an object with `match` function, which + * defines how this object should be matched by TS-Pattern. + * + * Note that this api is unstable. + * + * @example + * ```ts + * class Some implements P.unstable_Matchable { + * [P.matcher](): P.unstable_Matcher> + * } + * ``` + */ +export type unstable_Matcher< + narrowedOrFn, + input = unknown, + pattern = never +> = ReturnType[matcher]>; + /** * `P.infer` will return the type of the value * matched by this pattern. @@ -682,15 +723,3 @@ export function typed(): { when: when as any, }; } - -export type Matchable< - narrowFn extends Fn, - input = unknown, - pattern = never -> = CustomP; - -export type Matcher< - narrowFn extends Fn, - input = unknown, - pattern = never -> = ReturnType[matcher]>; diff --git a/src/types/InvertPattern.ts b/src/types/InvertPattern.ts index ee3bdf2d..091656e0 100644 --- a/src/types/InvertPattern.ts +++ b/src/types/InvertPattern.ts @@ -112,7 +112,7 @@ type InvertPatternInternal = 0 extends 1 & p infer subpattern, infer matcherType, any, - infer narrowFn + infer narrowedOrFn > ? { not: DeepExclude>; @@ -133,7 +133,9 @@ type InvertPatternInternal = 0 extends 1 & p and: ReduceIntersection, input>; or: ReduceUnion, input>; default: [subpattern] extends [never] ? input : subpattern; - custom: Override : never>; + custom: Override< + narrowedOrFn extends Fn ? Apply : narrowedOrFn + >; }[matcherType] : p extends Primitives ? p @@ -341,9 +343,9 @@ type InvertPatternForExcludeInternal = InvertPatternForExcludeInternal >; default: excluded; - custom: excluded extends infer narrowFn extends Fn - ? Apply - : never; + custom: excluded extends infer narrowedOrFn extends Fn + ? Apply + : excluded; }[matcherType] : p extends readonly any[] ? Extract extends infer arrayInput diff --git a/src/types/Pattern.ts b/src/types/Pattern.ts index 0f240152..890974ad 100644 --- a/src/types/Pattern.ts +++ b/src/types/Pattern.ts @@ -78,7 +78,7 @@ export type AnyMatcher = Matcher; type UnknownMatcher = Matcher; -export type CustomP = Matcher< +export type CustomP = Matcher< input, pattern, // 👆 @@ -86,7 +86,7 @@ export type CustomP = Matcher< // on subpatterns, it has to be passed through. 'custom', None, - narrowFn + narrowedOrFn >; export type ArrayP = Matcher; diff --git a/tests/matcher-protocol.test.ts b/tests/matcher-protocol.test.ts index bfd461ce..fc245843 100644 --- a/tests/matcher-protocol.test.ts +++ b/tests/matcher-protocol.test.ts @@ -1,20 +1,17 @@ import { isMatching, match, P } from '../src'; -import { Equal, Expect, Fn } from '../src/types/helpers'; -import { UnknownPattern } from '../src/types/Pattern'; +import { Equal, Expect } from '../src/types/helpers'; describe('matcher protocol', () => { type SomeValue = T extends Some ? V : never; - interface SomeNarrowFn

= never> extends Fn { - output: [p] extends [never] - ? Some> - : Some, p>>; + interface SomeNarrowFn extends P.unstable_Fn { + output: Some>; } class Some { constructor(public value: T) {} - static [P.matcher](): P.Matcher { + static [P.matcher](): P.unstable_Matcher { return { match: (input) => { return { @@ -24,7 +21,9 @@ describe('matcher protocol', () => { }; } - [P.matcher](): P.Matcher>> { + [P.matcher](): P.unstable_Matcher< + Some ? P.infer : T> + > { return { match: (input) => { return { @@ -35,15 +34,13 @@ describe('matcher protocol', () => { }; } } - interface NoneNarrowFn extends Fn { - output: None; - } + class None { coucou: number; constructor() { this.coucou = 1; } - static [P.matcher](): P.Matcher { + static [P.matcher](): P.unstable_Matcher { return { match: (input) => { return { matched: input instanceof None };