UNPKG

ts-switch-case

Version:

A TypeScript-first switch-case utility with object-based and chainable syntax

113 lines (110 loc) 5.13 kB
/** * Utility type to extract the variant of a discriminated union. * * @template T - The union type. * @template K - The discriminator key. * @template V - The discriminator value. */ type VariantOf<T, K extends keyof T, V> = T extends Record<K, V> ? T : never; /** * Represents a handler for a case in a switch-case structure. * * @template T - The type of the value being matched. * @template R - The return type of the handler function. * @property {T} match - A value or a function to match against the input. * @property {(val: T) => R} handler - A function that processes the matched value and returns a result. */ type CaseHandler<T, R> = { match: T; handler: (val: T) => R; } | { match: (val: T) => boolean; handler: (val: T) => R; }; /** * Interface for building a switch-case structure with fluent API. * * @template T - The type of the value being matched. * @template R - The return type of the handler functions. * @template Remaining - The remaining keys that can be matched. */ interface SwitchCaseBuilder<T, R, Remaining extends string | number | symbol = never> { /** * Adds a case to the switch-case structure. * * @template K - The type of the key being matched. * @param {K} match - A value to match or a function to evaluate the match. * @param {R | (() => R)} handler - A result or a function that returns a result for the matched case. * @returns {SwitchCaseBuilder<T, R, Exclude<Remaining, K>>} - The updated builder with the new case added. */ case: (<K extends Remaining>(match: K, handler: R | (() => R)) => SwitchCaseBuilder<T, R, Exclude<Remaining, K>>) & ((match: (val: T) => boolean, handler: R | ((val: T) => R)) => SwitchCaseBuilder<T, R, Remaining>); /** * Adds a default handler for unmatched cases. * * @param {(val: T) => R} handler - A function to handle unmatched cases. * @returns {SwitchCaseBuilder<T, R, never>} - The updated builder with the default handler added. */ default: (handler: (val: T) => R) => SwitchCaseBuilder<T, R, never>; /** * Ensures all cases are handled and returns the result. * * @returns {Remaining extends never ? R : never} - The result of the matched case or an error if cases are missing. */ exhaustive: () => Remaining extends never ? R : never; /** * Executes the switch-case structure and returns the result. * * @returns {R} - The result of the matched case or the default handler. */ run: () => R; } /** * Interface for building a discriminated union switch-case structure with fluent API. * * @template T - The type of the value being matched. * @template K - The discriminator key. * @template R - The return type of the handler functions. * @template Remaining - The remaining discriminator values that can be matched. */ interface DiscriminatedUnionSwitchCaseBuilder<T, K extends keyof T, R, Remaining extends string | number | symbol = string | number | symbol> { /** * Adds a case for a specific discriminator value. * * @template V - The discriminator value. * @param {V} value - The discriminator value to match. * @param {(val: VariantOf<T, K, V>) => R} handler - Handler for this case. * @returns {DiscriminatedUnionSwitchCaseBuilder<T, K, R, Exclude<Remaining, V>>} */ case: <V extends Remaining>(value: V, handler: (val: VariantOf<T, K, V>) => R) => DiscriminatedUnionSwitchCaseBuilder<T, K, R, Exclude<Remaining, V>>; /** * Adds a default handler for unmatched cases. * * @param {(val: T) => R} handler - Handler for unmatched cases. * @returns {DiscriminatedUnionSwitchCaseBuilder<T, K, R, never>} */ default: (handler: (val: T) => R) => DiscriminatedUnionSwitchCaseBuilder<T, K, R, never>; /** * Executes the switch-case structure and returns the result. * * @returns {R} - The result of the matched case or the default handler. */ run: () => R; } declare function switchCase<T extends string | number | symbol, R>(value: T, cases: { [K in T]: R | (() => R); }, defaultHandler?: (val: T) => R): R; declare function switchCase<T, K extends keyof T, V extends T[K] & (string | number), R>(value: T, discriminator: K, cases: { [P in V]: R | ((val: T & { [Q in K]: P; }) => R); }, defaultHandler?: (val: T) => R): R; declare function switchCase<T, R>(value: T, cases: Record<string, CaseHandler<T, R>>, defaultHandler?: (val: T) => R): R; declare function switchCase<T, R>(value: T, cases: Array<{ match: (val: T) => boolean; handler: R | ((val: T) => R); }>, defaultHandler?: (val: T) => R): R; declare function switchCase<T extends string | number | symbol, R>(value: T): SwitchCaseBuilder<T, R, T>; declare function switchCase<T, R>(value: T): SwitchCaseBuilder<T, R, never>; declare function switchCase<T, K extends keyof T, R>(value: T, discriminator: K): DiscriminatedUnionSwitchCaseBuilder<T, K, R, T[K] & (string | number | symbol)>; declare function assertUnreachable(value: never): never; export { assertUnreachable, switchCase };