ts-pattern
Version:
The exhaustive Pattern Matching library for TypeScript.
66 lines (65 loc) • 4.25 kB
text/typescript
import type * as symbols from '../internals/symbols.cjs';
import type { AnyMatcher, Matcher, Pattern } from './Pattern.cjs';
import type { Equal, Primitives, ValueOf, MergeUnion, IsUnion } from './helpers.cjs';
type SelectionsRecord = Record<string, [unknown, unknown[]]>;
export type None = {
type: 'none';
};
export type Some<key extends string> = {
type: 'some';
key: key;
};
export type SelectionType = None | Some<string>;
type MapOptional<selections> = {
[k in keyof selections]: selections[k] extends [infer v, infer subpath] ? [v | undefined, subpath] : never;
};
type MapList<selections> = {
[k in keyof selections]: selections[k] extends [infer v, infer subpath] ? [v[], subpath] : never;
};
type ReduceFindSelectionUnion<i, ps extends readonly any[], output = never> = ps extends readonly [infer head, ...infer tail] ? ReduceFindSelectionUnion<i, tail, output | FindSelectionUnion<i, head>> : output;
type FindSelectionUnionInArray<i, p, path extends any[] = [], output = never> = i extends readonly (infer iItem)[] ? p extends readonly [] ? output : p extends readonly [infer p1, ...infer pRest] ? i extends readonly [infer i1, ...infer iRest] ? FindSelectionUnionInArray<iRest, pRest, [
...path,
p['length']
], output | FindSelectionUnion<i1, p1, [...path, p['length']]>> : FindSelectionUnionInArray<iItem[], pRest, [
...path,
p['length']
], output | FindSelectionUnion<iItem, p1, [...path, p['length']]>> : p extends readonly [...infer pInit, infer p1] ? i extends readonly [...infer iInit, infer i1] ? FindSelectionUnionInArray<iInit, pInit, [
...path,
p['length']
], output | FindSelectionUnion<i1, p1, [...path, p['length']]>> : FindSelectionUnionInArray<iItem[], pInit, [
...path,
p['length']
], output | FindSelectionUnion<iItem, p1, [...path, p['length']]>> : p extends readonly [...(readonly (infer pRest & AnyMatcher)[])] ? output | FindSelectionUnion<i, pRest, [...path, p['length']]> : output | FindSelectionUnion<iItem, ValueOf<p>, [
...path,
Extract<p, readonly any[]>['length']
]> : output;
export type FindSelectionUnion<i, p, path extends any[] = []> = 0 extends 1 & i ? never : 0 extends 1 & p ? never : p extends Primitives ? never : p extends Matcher<any, infer pattern, infer matcherType, infer sel> ? {
select: sel extends Some<infer k> ? {
[kk in k]: [i, path];
} | FindSelectionUnion<i, pattern, path> : never;
array: i extends readonly (infer iItem)[] ? MapList<FindSelectionUnion<iItem, pattern>> : never;
map: never;
set: never;
optional: MapOptional<FindSelectionUnion<i, pattern>>;
or: MapOptional<ReduceFindSelectionUnion<i, Extract<pattern, readonly any[]>>>;
and: ReduceFindSelectionUnion<i, Extract<pattern, readonly any[]>>;
not: never;
default: sel extends Some<infer k> ? {
[kk in k]: [i, path];
} : never;
custom: never;
}[matcherType] : p extends readonly any[] ? FindSelectionUnionInArray<i, p> : p extends {} ? i extends {} ? {
[k in keyof p]: k extends keyof i ? FindSelectionUnion<i[k], p[k], [...path, k]> : never;
}[keyof p] : never : never;
export type SeveralAnonymousSelectError<a = 'You can only use a single anonymous selection (with `select()`) in your pattern. If you need to select multiple values, give them names with `select(<name>)` instead'> = {
__error: never;
} & a;
export type MixedNamedAndAnonymousSelectError<a = 'Mixing named selections (`select("name")`) and anonymous selections (`select()`) is forbiden. Please, only use named selections.'> = {
__error: never;
} & a;
export type SelectionToArgs<selections extends SelectionsRecord> = symbols.anonymousSelectKey extends keyof selections ? IsUnion<selections[symbols.anonymousSelectKey][1]> extends true ? SeveralAnonymousSelectError : keyof selections extends symbols.anonymousSelectKey ? selections[symbols.anonymousSelectKey][0] : MixedNamedAndAnonymousSelectError : {
[k in keyof selections]: selections[k][0];
};
export type Selections<i, p> = FindSelectionUnion<i, p> extends infer u ? [u] extends [never] ? i : SelectionToArgs<Extract<MergeUnion<u>, SelectionsRecord>> : i;
export type FindSelected<i, p> = Equal<p, Pattern<i>> extends true ? i : Selections<i, p>;
export {};