diff --git a/src/internals/match/Match.ts b/src/internals/match/Match.ts index 109c1c9..3769ea6 100644 --- a/src/internals/match/Match.ts +++ b/src/internals/match/Match.ts @@ -14,6 +14,7 @@ import * as Impl from "./impl/match"; * ```ts * type Test = Match>, + * WithExact, * With>, * With> * ]> @@ -21,12 +22,12 @@ import * as Impl from "./impl/match"; */ export type Match< valueOrWithClauses = unset, - withClauses extends Impl.With[] | unset | _ = unset + withClauses extends Impl.With[] | unset | _ = unset > = PartialApply< MatchFn, withClauses extends unset - ? [unset, valueOrWithClauses] - : [valueOrWithClauses, withClauses] + ? [unset, valueOrWithClauses] + : [valueOrWithClauses, withClauses] >; interface MatchFn extends Fn { @@ -35,4 +36,5 @@ interface MatchFn extends Fn { export namespace Match { export type With = Impl.With; + export type WithExact = Impl.WithExact; } diff --git a/src/internals/match/impl/match.ts b/src/internals/match/impl/match.ts index f549ea6..8f34b71 100644 --- a/src/internals/match/impl/match.ts +++ b/src/internals/match/impl/match.ts @@ -1,5 +1,5 @@ import { arg, Call, Fn, PartialApply, unset } from "../../core/Core"; -import { Primitive, UnionToIntersection } from "../../helpers"; +import { Primitive, UnionToIntersection, Equal } from "../../helpers"; type GetWithDefault = K extends keyof Obj ? Obj[K] : Def; @@ -18,7 +18,8 @@ type ReplaceArgsWithConstraint = pattern extends arg< ? { [key in keyof pattern]: ReplaceArgsWithConstraint } : pattern; -type DoesMatch = +type DoesMatch = exact extends true ? + Equal : value extends ReplaceArgsWithConstraint ? true : false; type ExtractArgObject = pattern extends arg @@ -26,22 +27,22 @@ type ExtractArgObject = pattern extends arg : pattern extends [] ? {} : [value, pattern] extends [ - [infer valueFirst, ...infer valueRest], - [infer patternFirst, ...infer patternRest] - ] + [infer valueFirst, ...infer valueRest], + [infer patternFirst, ...infer patternRest] + ] ? ExtractArgObject & - ExtractArgObject + ExtractArgObject : [value, pattern] extends [(infer valueFirst)[], (infer patternFirst)[]] ? ExtractArgObject : [value, pattern] extends [object, object] ? UnionToIntersection< - { - [k in keyof value & keyof pattern]: ExtractArgObject< - value[k], - pattern[k] - >; - }[keyof value & keyof pattern] - > + { + [k in keyof value & keyof pattern]: ExtractArgObject< + value[k], + pattern[k] + >; + }[keyof value & keyof pattern] + > : {}; type WithDefaultArgs = [Args[number]] extends [unset] @@ -60,15 +61,16 @@ type ExtractArgs = WithDefaultArgs< [value] >; -export type Match[]> = patterns extends [ - With, - ...infer restPatterns extends With[] +export type Match[]> = patterns extends [ + With, + ...infer restPatterns extends With[] ] - ? DoesMatch extends true - ? handler extends Fn - ? Call, ExtractArgs>> - : handler - : Match + ? DoesMatch extends true + ? handler extends Fn + ? Call, ExtractArgs>> + : handler + : Match : never; -export type With = { pattern: pattern; handler: handler }; +export type With = { exact: exact; pattern: pattern; handler: handler }; +export type WithExact = With; diff --git a/test/match.test.ts b/test/match.test.ts index 19d4967..1ab8651 100644 --- a/test/match.test.ts +++ b/test/match.test.ts @@ -110,6 +110,38 @@ describe("Match", () => { type test3 = Expect>; }); + it("should match with exact types", () => { + type MatchTest = Call< + Match< + T, + [ + Match.WithExact<{ msg: string }, Constant<"string">>, + Match.WithExact<{ msg: string; x: number }, Constant<"string + x">>, + Match.WithExact<{ msg: string; x: number; y: boolean }, Constant<"all">>, + Match.With> + ] + > + >; + + type res1 = MatchTest<{ msg: string }>; + // ^? + type test1 = Expect>; + + type res2 = MatchTest<{ msg: string; x: number }>; + // ^? + type test2 = Expect>; + + type res3 = MatchTest<{ msg: string; x: number; y: boolean }>; + // ^? + type test3 = Expect>; + + type res4 = MatchTest<{ msg: "hello" }>; + // ^? + type test4 = Expect>; + + + }); + it("Handlers can also be regular values", () => { type MatchTest = Call< Match<