···11import { pipe } from "../prelude/compose"
22-import { some, none, type Option } from "../prelude/option"
22+import { none, type Option, some } from "../prelude/option"
3344// Phantom property type
55declare const __props: unique symbol
···1919export const arr = <T>(xs: readonly T[]): Arr<T> => xs as Arr<T>
20202121// NonEmpty check - returns Option to track the property
2222-export const nonEmpty = <T, P extends string>(xs: Arr<T, P>): Option<Arr<T, P | NonEmpty>> =>
2222+export const nonEmpty = <T, P extends string>(
2323+ xs: Arr<T, P>,
2424+): Option<Arr<T, P | NonEmpty>> =>
2325 xs.length > 0 ? some(xs as Arr<T, P | NonEmpty>) : none
24262527// Safe accessors for NonEmpty arrays
2628export const head = <T, P extends string>(xs: Arr<T, P | NonEmpty>): T => xs[0]!
2727-export const last = <T, P extends string>(xs: Arr<T, P | NonEmpty>): T => xs[xs.length - 1]!
2929+export const last = <T, P extends string>(xs: Arr<T, P | NonEmpty>): T =>
3030+ xs[xs.length - 1]!
28312932// Sorting - adds Sorted property
3030-export const sortNum = <P extends string>(xs: Arr<number, P>): Arr<number, P | Sorted> =>
3333+export const sortNum = <P extends string>(
3434+ xs: Arr<number, P>,
3535+): Arr<number, P | Sorted> =>
3136 [...xs].sort((a, b) => a - b) as Arr<number, P | Sorted>
32373333-export const sortBy = <T, P extends string>(key: (t: T) => number) =>
3838+export const sortBy =
3939+ <T, P extends string>(key: (t: T) => number) =>
3440 (xs: Arr<T, P>): Arr<T, P | Sorted> =>
3541 [...xs].sort((a, b) => key(a) - key(b)) as Arr<T, P | Sorted>
36423743// Transformations - preserve properties where valid
3838-export const map = <T, U>(f: (t: T) => U) =>
4444+export const map =
4545+ <T, U>(f: (t: T) => U) =>
3946 <P extends string>(xs: Arr<T, P>): Arr<U, Exclude<P, Sorted>> =>
4047 xs.map(f) as Arr<U, Exclude<P, Sorted>>
41484242-export const filter = <T>(pred: (t: T) => boolean) =>
4949+export const filter =
5050+ <T>(pred: (t: T) => boolean) =>
4351 <P extends string>(xs: Arr<T, P>): Arr<T, Exclude<P, NonEmpty>> =>
4452 xs.filter(pred) as Arr<T, Exclude<P, NonEmpty>>
45534646-export const reduce = <T, U>(f: (acc: U, t: T) => U, initial: U) =>
5454+export const reduce =
5555+ <T, U>(f: (acc: U, t: T) => U, initial: U) =>
4756 <P extends string>(xs: Arr<T, P>): U =>
4857 xs.reduce(f, initial)
49585059// Take/drop
5151-export const take = (n: number) =>
6060+export const take =
6161+ (n: number) =>
5262 <T, P extends string>(xs: Arr<T, P>): Arr<T, Exclude<P, NonEmpty>> =>
5363 xs.slice(0, n) as Arr<T, Exclude<P, NonEmpty>>
54645555-export const drop = (n: number) =>
6565+export const drop =
6666+ (n: number) =>
5667 <T, P extends string>(xs: Arr<T, P>): Arr<T, Exclude<P, NonEmpty>> =>
5768 xs.slice(n) as Arr<T, Exclude<P, NonEmpty>>
58695970// Generic binary search with comparator
6060-export const binarySearch = <T>(compare: (a: T, b: T) => number) =>
7171+export const binarySearch =
7272+ <T>(compare: (a: T, b: T) => number) =>
6173 (target: T) =>
6262- <P extends string>(xs: Arr<T, P | Sorted>): Option<number> => {
6363- const go = (lo: number, hi: number): Option<number> =>
6464- lo > hi
6565- ? none
6666- : pipe(
6767- Math.floor((lo + hi) / 2),
6868- mid => (
6969- (cmp => cmp === 0 ? some(mid) : cmp < 0 ? go(lo, mid - 1) : go(mid + 1, hi))
7070- (compare(target, xs[mid]!))
7171- )
7272- )
7373- return go(0, xs.length - 1)
7474- }
7474+ <P extends string>(xs: Arr<T, P | Sorted>): Option<number> => {
7575+ const go = (lo: number, hi: number): Option<number> =>
7676+ lo > hi
7777+ ? none
7878+ : pipe(Math.floor((lo + hi) / 2), (mid) =>
7979+ ((cmp) =>
8080+ cmp === 0
8181+ ? some(mid)
8282+ : cmp < 0
8383+ ? go(lo, mid - 1)
8484+ : go(mid + 1, hi))(compare(target, xs[mid]!)),
8585+ )
8686+ return go(0, xs.length - 1)
8787+ }
75887689// Binary search specialized for numbers
7790export const binarySearchNum = binarySearch<number>((a, b) => a - b)
+20-15
src/data/guards.ts
···1818export const isBoolean = (x: unknown): x is boolean => typeof x === "boolean"
19192020/** Type guard for non-null object values */
2121-export const isObject = (x: unknown): x is object => typeof x === "object" && x !== null
2121+export const isObject = (x: unknown): x is object =>
2222+ typeof x === "object" && x !== null
22232324/** Type guard for array values */
2425export const isArray = (x: unknown): x is unknown[] => Array.isArray(x)
···3435export const isNegative = (x: unknown): x is number => isNumber(x) && x < 0
35363637/** Type guard for integer numbers */
3737-export const isInteger = (x: unknown): x is number => isNumber(x) && Number.isInteger(x)
3838+export const isInteger = (x: unknown): x is number =>
3939+ isNumber(x) && Number.isInteger(x)
38403941/** Type guard for finite numbers (excludes Infinity and NaN) */
4040-export const isFiniteNumber = (x: unknown): x is number => isNumber(x) && Number.isFinite(x)
4242+export const isFiniteNumber = (x: unknown): x is number =>
4343+ isNumber(x) && Number.isFinite(x)
41444245// =============================================================================
4346// Guard Combinators
4447// =============================================================================
45484649/** Combines two guards with logical AND - both must pass */
4747-export const and = <A, B extends A, C extends B>(
4848- g1: (x: A) => x is B,
4949- g2: (x: B) => x is C
5050-) => (x: A): x is C => g1(x) && g2(x)
5050+export const and =
5151+ <A, B extends A, C extends B>(g1: (x: A) => x is B, g2: (x: B) => x is C) =>
5252+ (x: A): x is C =>
5353+ g1(x) && g2(x)
51545255/** Combines two guards with logical OR - either must pass */
5353-export const or = <A, B extends A, C extends A>(
5454- g1: (x: A) => x is B,
5555- g2: (x: A) => x is C
5656-) => (x: A): x is B | C => g1(x) || g2(x)
5656+export const or =
5757+ <A, B extends A, C extends A>(g1: (x: A) => x is B, g2: (x: A) => x is C) =>
5858+ (x: A): x is B | C =>
5959+ g1(x) || g2(x)
57605861/** Negates a guard */
5959-export const not = <A, B extends A>(
6060- guard: (x: A) => x is B
6161-) => (x: A): x is Exclude<A, B> => !guard(x)
6262+export const not =
6363+ <A, B extends A>(guard: (x: A) => x is B) =>
6464+ (x: A): x is Exclude<A, B> =>
6565+ !guard(x)
62666367// =============================================================================
6468// Property Guards
6569// =============================================================================
66706771/** Creates a guard that checks if an object has a specific property */
6868-export const hasProperty = <K extends string>(key: K) =>
7272+export const hasProperty =
7373+ <K extends string>(key: K) =>
6974 <T>(x: T): x is T & Record<K, unknown> =>
7075 isObject(x) && key in x
+2-2
src/data/index.ts
···44 * @module data
55 */
6677-export * from "./guards"
87export * from "./array"
99-export * from "./units"
108export * from "./entity"
99+export * from "./guards"
1010+export * from "./units"
1111export * from "./validation"
···11-export * from "./exit"
11+export * from "./combinators"
22export * from "./eff"
33-export * from "./step"
33+export * from "./exit"
44export * from "./interpret"
55+export * from "./step"
56export * from "./trampoline"
66-export * from "./combinators"
+57-37
src/effect/interpret.ts
···11import { match } from "../prelude/match"
22import type { Eff, Fiber, FiberId } from "./eff"
33import { makeFiberId } from "./eff"
44-import { matchExit, type Exit } from "./exit"
55-import { suspended, blocked, type Step } from "./step"
44+import { type Exit, matchExit } from "./exit"
55+import { blocked, type Step, suspended } from "./step"
6677/**
88 * Continuation - what to do with the result of an effect.
···2121export const interpret = <A, E, R>(
2222 eff: Eff<A, E, R>,
2323 cont: Continuation<A, E, R>,
2424- makeFiber: <A2, E2>(eff: Eff<A2, E2, R>, env: R) => Fiber<A2, E2>
2424+ makeFiber: <A2, E2>(eff: Eff<A2, E2, R>, env: R) => Fiber<A2, E2>,
2525): Step<unknown, unknown> =>
2626 match(eff)({
2727 Succeed: ({ value }) => cont.onSuccess(value),
28282929 Fail: ({ error }) => cont.onFailure(error),
30303131- Sync: ({ f }) => suspended(() => {
3232- try {
3333- return cont.onSuccess(f())
3434- } catch (e) {
3535- return cont.onFailure(e as E)
3636- }
3737- }),
3131+ Sync: ({ f }) =>
3232+ suspended(() => {
3333+ try {
3434+ return cont.onSuccess(f())
3535+ } catch (e) {
3636+ return cont.onFailure(e as E)
3737+ }
3838+ }),
38393940 Async: ({ register }) => {
4041 let result: Exit<A, E> | null = null
4142 let callback: (() => void) | null = null
42434343- const cleanup = register(exit => {
4444+ const cleanup = register((exit) => {
4445 result = exit
4546 callback?.()
4647 })
47484849 const handleExit = matchExit<A, E, Step<unknown, unknown>>(
4949- value => cont.onSuccess(value),
5050- error => cont.onFailure(error),
5151- () => cont.onFailure("interrupted" as E)
5050+ (value) => cont.onSuccess(value),
5151+ (error) => cont.onFailure(error),
5252+ () => cont.onFailure("interrupted" as E),
5253 )
53545455 // Handle synchronous completion
···58595960 return blocked(
6061 cleanup,
6161- cb => { callback = cb },
6262- () => handleExit(result!)
6262+ (cb) => {
6363+ callback = cb
6464+ },
6565+ () => handleExit(result!),
6366 )
6467 },
65686666- FlatMap: ({ effect, f }) => suspended(() =>
6767- interpret(effect as Eff<unknown, E, R>, {
6868- env: cont.env,
6969- onSuccess: a => interpret(f(a) as Eff<A, E, R>, cont, makeFiber),
7070- onFailure: cont.onFailure
7171- }, makeFiber)
7272- ),
6969+ FlatMap: ({ effect, f }) =>
7070+ suspended(() =>
7171+ interpret(
7272+ effect as Eff<unknown, E, R>,
7373+ {
7474+ env: cont.env,
7575+ onSuccess: (a) => interpret(f(a) as Eff<A, E, R>, cont, makeFiber),
7676+ onFailure: cont.onFailure,
7777+ },
7878+ makeFiber,
7979+ ),
8080+ ),
73817474- Fold: ({ effect, onErr, onSucc }) => suspended(() =>
7575- interpret(effect as Eff<unknown, unknown, R>, {
7676- env: cont.env,
7777- onSuccess: a => interpret(onSucc(a) as Eff<A, E, R>, cont, makeFiber),
7878- onFailure: e => interpret(onErr(e) as Eff<A, E, R>, cont, makeFiber)
7979- }, makeFiber)
8080- ),
8282+ Fold: ({ effect, onErr, onSucc }) =>
8383+ suspended(() =>
8484+ interpret(
8585+ effect as Eff<unknown, unknown, R>,
8686+ {
8787+ env: cont.env,
8888+ onSuccess: (a) =>
8989+ interpret(onSucc(a) as Eff<A, E, R>, cont, makeFiber),
9090+ onFailure: (e) =>
9191+ interpret(onErr(e) as Eff<A, E, R>, cont, makeFiber),
9292+ },
9393+ makeFiber,
9494+ ),
9595+ ),
81968297 Access: ({ f }) => cont.onSuccess(f(cont.env)),
83988484- AccessEff: ({ f }) => suspended(() =>
8585- interpret(f(cont.env), cont, makeFiber)
8686- ),
9999+ AccessEff: ({ f }) =>
100100+ suspended(() => interpret(f(cont.env), cont, makeFiber)),
871018888- Provide: ({ effect, env }) => suspended(() =>
8989- interpret(effect as Eff<A, E, R>, { ...cont, env: env as R }, makeFiber)
9090- ),
102102+ Provide: ({ effect, env }) =>
103103+ suspended(() =>
104104+ interpret(
105105+ effect as Eff<A, E, R>,
106106+ { ...cont, env: env as R },
107107+ makeFiber,
108108+ ),
109109+ ),
9111092111 Fork: ({ effect }) => {
93112 const fiber = makeFiber(effect, cont.env)
···9611597116 YieldNow: () => suspended(() => cont.onSuccess(undefined as A)),
981179999- GetFiberId: () => cont.onSuccess((cont.fiberId ?? makeFiberId()) as unknown as A)
118118+ GetFiberId: () =>
119119+ cont.onSuccess((cont.fiberId ?? makeFiberId()) as unknown as A),
100120 })
···11import { match } from "../prelude/match"
22import type { Option } from "../prelude/option"
33-import { some, none, matchOption } from "../prelude/option"
33+import { matchOption, none, some } from "../prelude/option"
44import type { Eff, Fiber, FiberId } from "./eff"
55-import { makeFiberId, async as asyncEff } from "./eff"
55+import { async as asyncEff, makeFiberId } from "./eff"
66import type { Exit } from "./exit"
77-import { success, failure, interrupted } from "./exit"
88-import { done, type Step } from "./step"
77+import { failure, interrupted, success } from "./exit"
98import { interpret } from "./interpret"
99+import { done, type Step } from "./step"
10101111/**
1212 * ESCAPE HATCH: The boundary between pure effect interpretation and JS execution.
···4141 Promise.resolve().then(() => trampoline(resume())),
42424343 Blocked: ({ onComplete, next }) =>
4444- new Promise(resolve => {
4444+ new Promise((resolve) => {
4545 onComplete(() => resolve(trampoline(next())))
4646- })
4646+ }),
4747 })
48484949// Fiber counter for unique IDs
···61616262 const makeFiberFn = <A2, E2>(e: Eff<A2, E2, R>, r: R) => createFiber(e, r)
63636464- const initialStep = interpret(eff, {
6565- env,
6666- fiberId: fId,
6767- onSuccess: (a: A) => done(success(a)),
6868- onFailure: (e: E) => done(failure(e))
6969- }, makeFiberFn) as Step<A, E>
6464+ const initialStep = interpret(
6565+ eff,
6666+ {
6767+ env,
6868+ fiberId: fId,
6969+ onSuccess: (a: A) => done(success(a)),
7070+ onFailure: (e: E) => done(failure(e)),
7171+ },
7272+ makeFiberFn,
7373+ ) as Step<A, E>
70747175 // Start execution
7272- trampoline(initialStep).then(exit => {
7373- const finalExit: Exit<A, E> = isInterrupted ? interrupted(id) as Exit<A, E> : exit
7676+ trampoline(initialStep).then((exit) => {
7777+ const finalExit: Exit<A, E> = isInterrupted
7878+ ? (interrupted(id) as Exit<A, E>)
7979+ : exit
7480 exitResult = some(finalExit)
7575- awaiters.forEach(cb => cb(finalExit))
8181+ awaiters.forEach((cb) => cb(finalExit))
7682 })
77837884 const fiber: Fiber<A, E> = {
7985 _tag: "Fiber",
8086 id,
8181- await: () => matchOption(
8282- (exit: Exit<A, E>) => Promise.resolve(exit),
8383- () => new Promise<Exit<A, E>>(resolve => awaiters.push(resolve))
8484- )(exitResult),
8585- interrupt: () => { isInterrupted = true },
8686- join: (): Eff<A, E, unknown> => asyncEff(resume => {
8787- fiber.await().then(resume)
8888- return () => {}
8989- })
8787+ await: () =>
8888+ matchOption(
8989+ (exit: Exit<A, E>) => Promise.resolve(exit),
9090+ () => new Promise<Exit<A, E>>((resolve) => awaiters.push(resolve)),
9191+ )(exitResult),
9292+ interrupt: () => {
9393+ isInterrupted = true
9494+ },
9595+ join: (): Eff<A, E, unknown> =>
9696+ asyncEff((resume) => {
9797+ fiber.await().then(resume)
9898+ return () => {}
9999+ }),
90100 }
91101 return fiber
92102}
···100110/**
101111 * Run an effect and return a Promise of the Exit.
102112 */
103103-export const runPromiseExit = <A, E>(eff: Eff<A, E, unknown>): Promise<Exit<A, E>> =>
104104- runFiber(eff, {}).await()
113113+export const runPromiseExit = <A, E>(
114114+ eff: Eff<A, E, unknown>,
115115+): Promise<Exit<A, E>> => runFiber(eff, {}).await()
105116106117/**
107118 * Run an effect and return a Promise of the success value.
108119 * Throws if the effect fails.
109120 */
110121export const runPromise = <A>(eff: Eff<A, unknown, unknown>): Promise<A> =>
111111- runPromiseExit(eff).then(exit =>
122122+ runPromiseExit(eff).then((exit) =>
112123 match(exit)({
113124 Success: ({ value }) => value,
114114- Failure: ({ error }) => { throw error },
115115- Interrupted: ({ by }) => { throw new Error(`Interrupted by ${by}`) }
116116- })
125125+ Failure: ({ error }) => {
126126+ throw error
127127+ },
128128+ Interrupted: ({ by }) => {
129129+ throw new Error(`Interrupted by ${by}`)
130130+ },
131131+ }),
117132 )
118133119134/**
120135 * Run an effect with provided environment.
121136 */
122122-export const runPromiseWith = <A, E, R>(env: R) =>
137137+export const runPromiseWith =
138138+ <A, E, R>(env: R) =>
123139 (eff: Eff<A, E, R>): Promise<Exit<A, E>> =>
124140 runFiber(eff, env).await()
+2-2
src/index.ts
···88 * - Fiber-based concurrency (cancellation, racing, parallelism)
99 */
10101111+export * from "./data"
1212+export * from "./effect"
1113// Re-export all public API from modular structure
1214export * from "./prelude"
1313-export * from "./data"
1414-export * from "./effect"
+7-6
src/prelude/brand.ts
···11import type { Option } from "./option"
22-import { some, none } from "./option"
22+import { none, some } from "./option"
3344// Brand symbol for nominal typing
55declare const __brand: unique symbol
···2929 * Create a refinement validator.
3030 * Returns Option to avoid throwing on invalid input.
3131 */
3232-export const refine = <T, R>(predicate: (value: T) => boolean) =>
3232+export const refine =
3333+ <T, R>(predicate: (value: T) => boolean) =>
3334 (value: T): Option<Refined<T, R>> =>
3435 predicate(value) ? some(value as Refined<T, R>) : none
3536···3940export type Normalized = "Normalized"
4041export type Integer = "Integer"
41424242-export const positive = refine<number, Positive>(x => x > 0)
4343-export const nonNegative = refine<number, NonNegative>(x => x >= 0)
4444-export const normalized = refine<number, Normalized>(x => x >= 0 && x <= 1)
4545-export const integer = refine<number, Integer>(x => Number.isInteger(x))
4343+export const positive = refine<number, Positive>((x) => x > 0)
4444+export const nonNegative = refine<number, NonNegative>((x) => x >= 0)
4545+export const normalized = refine<number, Normalized>((x) => x >= 0 && x <= 1)
4646+export const integer = refine<number, Integer>((x) => Number.isInteger(x))
+16-10
src/prelude/compose.ts
···2828 * always42() // 42
2929 * ```
3030 */
3131-export const constant = <A>(a: A) => (): A => a
3131+export const constant =
3232+ <A>(a: A) =>
3333+ (): A =>
3434+ a
32353336/**
3437 * Flip the arguments of a curried binary function.
···4144 * flipped(10)(3) // -7
4245 * ```
4346 */
4444-export const flip = <A, B, C>(f: (a: A) => (b: B) => C) =>
4747+export const flip =
4848+ <A, B, C>(f: (a: A) => (b: B) => C) =>
4549 (b: B) =>
4650 (a: A): C =>
4751 f(a)(b)
···6165 * // Returns: 84
6266 * ```
6367 */
6464-export const tap = <A>(f: (a: A) => void) =>
6868+export const tap =
6969+ <A>(f: (a: A) => void) =>
6570 (a: A): A => (f(a), a)
66716772/**
···7782 * )
7883 * ```
7984 */
8080-export const trace = <T>(label: string) => tap<T>(x => console.log(label, x))
8585+export const trace = <T>(label: string) => tap<T>((x) => console.log(label, x))
81868287/**
8388 * Conditional helper - choose between two functions based on a predicate.
···9196 * // Returns: "was true"
9297 * ```
9398 */
9494-export const ifElse = <T, E>(predicate: boolean) =>
9999+export const ifElse =
100100+ <T, E>(predicate: boolean) =>
95101 (onFalse: () => T | E, onTrue: () => T | E): T | E =>
96102 predicate ? onFalse() : onTrue()
97103···134140 a: A,
135141 ab: (a: A) => B,
136142 bc: (b: B) => C,
137137- cd: (c: C) => D
143143+ cd: (c: C) => D,
138144): D
139145export function pipe<A, B, C, D, E>(
140146 a: A,
141147 ab: (a: A) => B,
142148 bc: (b: B) => C,
143149 cd: (c: C) => D,
144144- de: (d: D) => E
150150+ de: (d: D) => E,
145151): E
146152export function pipe<A, B, C, D, E, F>(
147153 a: A,
···149155 bc: (b: B) => C,
150156 cd: (c: C) => D,
151157 de: (d: D) => E,
152152- ef: (e: E) => F
158158+ ef: (e: E) => F,
153159): F
154160export function pipe(
155161 a: unknown,
···189195export function flow<A, B, C, D>(
190196 ab: (a: A) => B,
191197 bc: (b: B) => C,
192192- cd: (c: C) => D
198198+ cd: (c: C) => D,
193199): (a: A) => D
194200export function flow<A, B, C, D, E>(
195201 ab: (a: A) => B,
196202 bc: (b: B) => C,
197203 cd: (c: C) => D,
198198- de: (d: D) => E
204204+ de: (d: D) => E,
199205): (a: A) => E
200206export function flow(
201207 ...fns: Array<(x: unknown) => unknown>
+3-3
src/prelude/index.ts
···11+export * from "./brand"
12export * from "./compose"
22-export * from "./result"
33-export * from "./option"
43export * from "./match"
55-export * from "./brand"
44+export * from "./option"
55+export * from "./result"
66export * from "./typeclasses"
+28-18
src/prelude/match.ts
···4141 * })
4242 * ```
4343 */
4444-export const match = <T extends { _tag: string }>(value: T) =>
4444+export const match =
4545+ <T extends { _tag: string }>(value: T) =>
4546 <R>(cases: { [K in T["_tag"]]: (v: Extract<T, { _tag: K }>) => R }): R =>
4647 (cases as unknown as Record<string, (v: T) => R>)[value._tag]!(value)
4748···6667 * })
6768 * ```
6869 */
6969-export const matchOr = <T extends { _tag: string }, R>(defaultValue: R) =>
7070+export const matchOr =
7171+ <T extends { _tag: string }, R>(defaultValue: R) =>
7072 (value: T) =>
7171- (cases: Partial<{ [K in T["_tag"]]: (v: Extract<T, { _tag: K }>) => R }>): R =>
7272- (cases as unknown as Record<string, ((v: T) => R) | undefined>)[value._tag] !== undefined
7373- ? (cases as unknown as Record<string, (v: T) => R>)[value._tag]!(value)
7474- : defaultValue
7373+ (
7474+ cases: Partial<{ [K in T["_tag"]]: (v: Extract<T, { _tag: K }>) => R }>,
7575+ ): R =>
7676+ (cases as unknown as Record<string, ((v: T) => R) | undefined>)[
7777+ value._tag
7878+ ] !== undefined
7979+ ? (cases as unknown as Record<string, (v: T) => R>)[value._tag]!(value)
8080+ : defaultValue
75817682/**
7783 * Guard-based pattern matching with predicates.
···105111 * )(() => "F")
106112 * ```
107113 */
108108-export const when = <T>(value: T) =>
114114+export const when =
115115+ <T>(value: T) =>
109116 <R>(...guards: ReadonlyArray<readonly [(v: T) => boolean, (v: T) => R]>) =>
110110- (defaultCase: (v: T) => R): R => {
111111- const go = (index: number): R =>
112112- index >= guards.length
113113- ? defaultCase(value)
114114- : guards[index]
115115- ? guards[index]
116116- : go(index + 1)
117117- return go(0)
118118- }
117117+ (defaultCase: (v: T) => R): R => {
118118+ const go = (index: number): R =>
119119+ index >= guards.length
120120+ ? defaultCase(value)
121121+ : guards[index]
122122+ ? guards[index]
123123+ : go(index + 1)
124124+ return go(0)
125125+ }
119126120127/**
121128 * Match on literal values (strings, numbers, booleans).
···145152 * }, "weekday")
146153 * ```
147154 */
148148-export const matchLiteral = <T extends string | number | boolean>(value: T) =>
155155+export const matchLiteral =
156156+ <T extends string | number | boolean>(value: T) =>
149157 <R>(cases: { [K in T & PropertyKey]: R }, defaultCase?: R): R =>
150150- (value as PropertyKey) in cases ? cases[value as T & PropertyKey] : (defaultCase as R)
158158+ (value as PropertyKey) in cases
159159+ ? cases[value as T & PropertyKey]
160160+ : (defaultCase as R)