UNPKG

type-plus

Version:
62 lines (59 loc) 1.91 kB
import type { IsNever } from '../never/never_type.js' import type { IsUnion } from '../union/union.js' import type { MergeOptions } from '../utils/options.js' /** * 🦴 *utilities* * 🔢 *customizable* * * Filter the element `T` in an array or tuple to match `Criteria`. * * @typeParam Options['widen'] Allow using narrow type to match widen type. * e.g. `number, 1` -> `1 | undefined`. * Default to `true`. * * @typeParam Options['caseNotMatch'] Return value when `T` does not match `Criteria`. * Default to `never`. * * @typeParam Options['caseWiden'] Return value when `widen` is true. * Default to `Criteria | undefined`. * * @typeParam Options['caseUnionNotMatch'] Return value when a branch of the union `T` does not match `Criteria`. * Default to `never`. * * If you want the type to behave more like JavaScript, * you can override it to return `undefined`. * * Since it is a union, the result will be joined to the matched branch as union. * e.g. `ElementMatch<1 | 2, 1>` -> `1 | undefined` */ export type ElementMatch< T, Criteria, Options extends ElementMatch.Options = ElementMatch.DefaultOptions<Criteria> > = [T] extends [Criteria] ? T : (MergeOptions<Options, ElementMatch.DefaultOptions<Criteria>> extends infer C extends Record<keyof ElementMatch.Options, unknown> ? ((T extends Criteria ? T : (C['widen'] extends true ? (Criteria extends T ? C['caseWiden'] : C['caseNotMatch']) : C['caseNotMatch'])) extends infer R ? IsUnion<T, IsNever<R, R, R | C['caseUnionNotMatch']>, R> : C['caseNotMatch']) : never) export namespace ElementMatch { export interface Options { widen?: boolean | undefined, caseNotMatch?: unknown, caseWiden?: unknown, caseUnionNotMatch?: unknown } export interface DefaultOptions<Criteria> { widen: true, caseNotMatch: never, caseWiden: Criteria | undefined, caseUnionNotMatch: never } }