Last active
April 25, 2023 14:42
-
-
Save lellimecnar/7f7764e371532054062c771fb358d2e1 to your computer and use it in GitHub Desktop.
Utils
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const MEMOIZE_RESULT = Symbol("MEMOIZE_RESULT"); | |
export interface MemoizeResolver<P extends any[], R extends any> { | |
(arg: P[number]): R; | |
} | |
export interface MemoizeCache<P extends any[], R extends any> { | |
get( | |
arg: P[0] | |
): P extends [any, ...infer Rest] ? MemoizeCache<Rest, R> | undefined : never; | |
get(arg: typeof MEMOIZE_RESULT): R | undefined; | |
set( | |
arg: P[0], | |
cache: P extends [any, ...infer Rest] ? MemoizeCache<Rest, R> : never | |
): void; | |
set(arg: typeof MEMOIZE_RESULT, value: R): void; | |
has(arg: P[0] | typeof MEMOIZE_RESULT): boolean; | |
clear(): void; | |
} | |
export interface Memoize { | |
<P extends any[], R extends any, K extends any>( | |
fn: (...params: P) => R, | |
resolver?: MemoizeResolver<P, K> | |
): typeof fn; | |
getCache<P extends any[], R extends any>( | |
fn: (...params: P) => R | |
): MemoizeCache<P, R>; | |
} | |
const memoizeCacheMap = new WeakMap<Function, MemoizeCache<any[], any>>(); | |
export const memoize = Object.defineProperties( | |
<P extends any[], R extends any, K extends any>( | |
fn: (...params: P) => R, | |
resolver?: MemoizeResolver<P, K>, | |
rootCache: MemoizeCache<P, R> = new Map() | |
) => { | |
const Cache = Object.getPrototypeOf(rootCache).constructor; | |
const memoized: typeof fn = (...params: P): R => { | |
const cache = params.reduce((thisCache, arg) => { | |
const key: K = typeof resolver === "function" ? resolver(arg) : arg; | |
if (!thisCache.has(key)) { | |
thisCache.set(key, new Cache()); | |
} | |
return thisCache.get(key); | |
}, rootCache); | |
if (!cache.has(MEMOIZE_RESULT)) { | |
cache.set(MEMOIZE_RESULT, fn(...params)); | |
} | |
return cache.get(MEMOIZE_RESULT); | |
}; | |
memoizeCacheMap.set(memoized, rootCache); | |
return memoized; | |
}, | |
{ | |
getCache: { | |
configurable: false, | |
writable: false, | |
enumerable: false, | |
value: (memoizedFn: Function) => memoizeCacheMap.get(memoizedFn), | |
}, | |
} | |
) as Memoize; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type PropertyPathKey< | |
P extends string | number, | |
K extends number | string | |
> = `${number}` extends `${K}` | |
? `${P}[${number}]` | `${P}.${number}` | |
: "" extends P | |
? K | |
: `${P}.${K}`; | |
type PropertyPathStr< | |
T extends Record<any, any>, | |
P extends string = "" | |
> = T extends ArrayLike<any> | |
? PropertyPathStr<Record<Extract<keyof T, number>, T[number]>, P> | |
: Exclude< | |
| P | |
| { | |
[K in Extract<keyof T, string | number>]: T[K] extends Record< | |
any, | |
any | |
> | |
? PropertyPathStr<T[K], PropertyPathKey<P, `${K}`>> | |
: PropertyPathKey<P, `${K}`>; | |
}[Extract<keyof T, string | number>], | |
"" | |
>; | |
type PropertyPathArray<T extends Record<any, any>> = | |
PropertyPathStr<T> extends `${infer P}` ? ExplodePath<P> : never; | |
type PropertyPath<T extends Record<string | number, any>> = | |
| PropertyPathArray<T> | |
| PropertyPathStr<T>; | |
type ExplodePath<P extends string> = "" extends P | |
? [] | |
: P extends `${infer K}.${infer Rest}` | |
? [...ExplodePath<K>, ...ExplodePath<Rest>] | |
: P extends `${infer K}[${infer Index}]${infer Rest}` | |
? [...ExplodePath<K>, number | Index, ...ExplodePath<Rest>] | |
: [P extends `${number}` ? number | P : P]; | |
type PropertyPathValue< | |
T extends Record<any, any>, | |
P extends PropertyPath<T> | |
> = P extends PropertyPathStr<T> & `${infer S}` | |
? PropertyPathValue<T, Extract<ExplodePath<S>, PropertyPathArray<T>>> | |
: [] extends P | |
? T | |
: P extends PropertyPathArray<T> & [infer K, ...infer Rest] | |
? K extends keyof T | |
? [] extends Rest | |
? T[K] | |
: Rest extends PropertyPathArray<T[K]> | |
? PropertyPathValue<T[K], Rest> | |
: T[K] | |
: never | |
: never; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment