An educational pure functional programming library in TypeScript
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add prelude/match module with exhaustive pattern matching

+41
+1
src/prelude/index.ts
··· 1 1 export * from "./compose" 2 2 export * from "./result" 3 3 export * from "./option" 4 + export * from "./match"
+40
src/prelude/match.ts
··· 1 + /** 2 + * Exhaustive pattern matching for discriminated unions. 3 + * Requires handlers for all variants - compiler enforces exhaustiveness. 4 + */ 5 + export const match = <T extends { _tag: string }>(value: T) => 6 + <R>(cases: { [K in T["_tag"]]: (v: Extract<T, { _tag: K }>) => R }): R => 7 + (cases as unknown as Record<string, (v: T) => R>)[value._tag]!(value) 8 + 9 + /** 10 + * Pattern matching with default case for partial matches. 11 + */ 12 + export const matchOr = <T extends { _tag: string }, R>(defaultValue: R) => 13 + (value: T) => 14 + (cases: Partial<{ [K in T["_tag"]]: (v: Extract<T, { _tag: K }>) => R }>): R => { 15 + const handler = (cases as unknown as Record<string, ((v: T) => R) | undefined>)[value._tag] 16 + return handler !== undefined ? handler(value) : defaultValue 17 + } 18 + 19 + /** 20 + * Guard-based pattern matching with predicates. 21 + * Evaluates guards in order, returns first match or default. 22 + */ 23 + export const when = <T>(value: T) => 24 + <R>(...guards: ReadonlyArray<readonly [(v: T) => boolean, (v: T) => R]>) => 25 + (defaultCase: (v: T) => R): R => { 26 + const go = (index: number): R => 27 + index >= guards.length 28 + ? defaultCase(value) 29 + : guards[index]![0](value) 30 + ? guards[index]![1](value) 31 + : go(index + 1) 32 + return go(0) 33 + } 34 + 35 + /** 36 + * Literal value matching. 37 + */ 38 + export const matchLiteral = <T extends string | number | boolean>(value: T) => 39 + <R>(cases: { [K in T & PropertyKey]: R }, defaultCase?: R): R => 40 + (value as PropertyKey) in cases ? cases[value as T & PropertyKey] : (defaultCase as R)