Skip to content

Commit

Permalink
perf: improve type checking performance of BuildMany
Browse files Browse the repository at this point in the history
  • Loading branch information
gvergnaud committed Sep 22, 2024
1 parent 67ec6a4 commit 8d23bc4
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 26 deletions.
54 changes: 37 additions & 17 deletions src/types/BuildMany.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Compute, Iterator, UpdateAt } from './helpers';
import { Iterator, UpdateAt, ValueOf } from './helpers';

// BuildMany :: DataStructure -> Union<[value, path][]> -> Union<DataStructure>
export type BuildMany<data, xs extends readonly any[]> = xs extends any
Expand All @@ -12,29 +12,49 @@ type BuildOne<data, xs extends readonly any[]> = xs extends [
[infer value, infer path],
...infer tail
]
? BuildOne<Update<data, value, Extract<path, readonly PropertyKey[]>>, tail>
? BuildOne<SetDeep<data, value, path>, tail>
: data;

// Update :: a -> b -> PropertyKey[] -> a
type Update<data, value, path> = path extends readonly [
// GetDeep :: a -> PropertyKey[] -> b
export type GetDeep<data, path> = path extends readonly [
infer head,
...infer tail
]
? data extends readonly [any, ...any]
? head extends number
? UpdateAt<data, Iterator<head>, Update<data[head], value, tail>>
: never
: data extends readonly (infer a)[]
? Update<a, value, tail>[]
? data extends readonly any[]
? data extends readonly [any, ...any]
? head extends number
? GetDeep<data[head], tail>
: never
: GetDeep<ValueOf<data>, tail>
: data extends Set<infer a>
? Set<Update<a, value, tail>>
? GetDeep<a, tail>
: data extends Map<any, infer v>
? GetDeep<v, tail>
: head extends keyof data
? GetDeep<data[head], tail>
: never
: data;

// SetDeep :: a -> b -> PropertyKey[] -> a
export type SetDeep<data, value, path> = path extends readonly [
infer head,
...infer tail
]
? data extends readonly any[]
? data extends readonly [any, ...any]
? head extends number
? UpdateAt<data, Iterator<head>, SetDeep<data[head], value, tail>>
: never
: SetDeep<ValueOf<data>, value, tail>[]
: data extends Set<infer a>
? Set<SetDeep<a, value, tail>>
: data extends Map<infer k, infer v>
? Map<k, Update<v, value, tail>>
? Map<k, SetDeep<v, value, tail>>
: head extends keyof data
? Compute<
{ [k in Exclude<keyof data, head>]: data[k] } & {
[k in head]: Update<data[k], value, tail>;
}
>
? {
[k in keyof data]-?: k extends head
? SetDeep<data[head], value, tail>
: data[k];
}
: data
: value;
18 changes: 9 additions & 9 deletions src/types/DistributeUnions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,15 +146,7 @@ export type FindUnions<
? IsStrictArray<Extract<a, readonly any[]>> extends false
? []
: [
MaybeAddReadonly<
| (a extends readonly [any, ...any] | readonly [...any, any]
? never
: [])
| (p extends readonly [...any, any]
? [...Extract<a, readonly any[]>, ValueOf<a>]
: [ValueOf<a>, ...Extract<a, readonly any[]>]),
IsReadonlyArray<a>
> extends infer aUnion
ArrayToVariadicUnion<a, p> extends infer aUnion
? {
cases: aUnion extends any
? {
Expand All @@ -179,6 +171,14 @@ export type FindUnions<
>
: [];

export type ArrayToVariadicUnion<input, excluded> = MaybeAddReadonly<
| (input extends readonly [any, ...any] | readonly [...any, any] ? never : [])
| (excluded extends readonly [...any, any]
? [...Extract<input, readonly any[]>, ValueOf<input>]
: [ValueOf<input>, ...Extract<input, readonly any[]>]),
IsReadonlyArray<input>
>;

// Distribute :: UnionConfig[] -> Union<[a, path][]>
export type Distribute<unions extends readonly any[]> =
unions extends readonly [
Expand Down

0 comments on commit 8d23bc4

Please sign in to comment.