-
Notifications
You must be signed in to change notification settings - Fork 6
/
index.ts
64 lines (53 loc) · 2.29 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
function pathToString(path: string[]): string {
return path.reduce((current, next) => {
if (+next === +next) {
current += `[${next}]`;
} else {
current += current === '' ? `${next}` : `.${next}`;
}
return current;
}, '');
}
export type TypedPathKey = string | symbol | number;
export type TypedPathFunction<T> = (...args: any[]) => T;
export type TypedPathHandlersConfig = Record<string, <T extends TypedPathHandlersConfig = Record<never, never>>(path: string[], additionalHandlers?: T) => any>;
const defaultHandlersConfig = {
$path: (path: string[]) => pathToString(path),
$raw: (path: string[]) => path,
toString: (path: string[]) => () => pathToString(path),
[Symbol.toStringTag]: (path: string[]) => () => pathToString(path),
valueOf: (path: string[]) => () => pathToString(path),
}
export type TypedPathHandlers<T extends TypedPathHandlersConfig> = {
[key in keyof T]: ReturnType<T[key]>;
};
export type TypedPathWrapper<T, TPH extends TypedPathHandlers<Record<never, never>>> = (T extends Array<infer Z>
? {
[index: number]: TypedPathWrapper<Z, TPH>;
}
: T extends TypedPathFunction<infer RET>
? {
(): TypedPathWrapper<RET, TPH>;
} & {
[P in keyof RET]: TypedPathWrapper<RET[P], TPH>;
}
: {
[P in keyof T]: TypedPathWrapper<T[P], TPH>;
}
) & TypedPathHandlers<TPH>;
export function typedPath<T, K extends TypedPathHandlersConfig = Record<never, never>>(additionalHandlers?: K, path: string[] = [], defaultsApplied: boolean = false): TypedPathWrapper<T, K & typeof defaultHandlersConfig> {
return <TypedPathWrapper<T, K & typeof defaultHandlersConfig>>new Proxy({}, {
get(target: T, name: TypedPathKey) {
let handlersConfig: TypedPathHandlersConfig;
if (defaultsApplied) {
handlersConfig = additionalHandlers!;
} else {
handlersConfig = { ...(additionalHandlers ?? {}), ...defaultHandlersConfig };
}
if (handlersConfig.hasOwnProperty(name)) {
return handlersConfig[name as any](path, additionalHandlers);
}
return typedPath(handlersConfig, [...path, name.toString()], true);
}
});
}