/
chain.ts
38 lines (36 loc) · 1.05 KB
/
chain.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
export type ChainableFunction<T extends string, Args extends any[], R = any, E = {}> = {
(...args: Args): R
} & {
[x in T]: ChainableFunction<T, Args, R, E>
} & {
fn: (this: Record<T, any>, ...args: Args) => R
} & E
export function createChainable<T extends string, Args extends any[], R = any, E = {}>(
keys: T[],
fn: (this: Record<T, any>, ...args: Args) => R,
): ChainableFunction<T, Args, R, E> {
function create(context: Record<T, any>) {
const chain = function (this: any, ...args: Args) {
return fn.apply(context, args)
}
Object.assign(chain, fn)
chain.withContext = () => chain.bind(context)
chain.setContext = (key: T, value: any) => {
context[key] = value
}
chain.mergeContext = (ctx: Record<T, any>) => {
Object.assign(context, ctx)
}
for (const key of keys) {
Object.defineProperty(chain, key, {
get() {
return create({ ...context, [key]: true })
},
})
}
return chain
}
const chain = create({} as any) as any
chain.fn = fn
return chain
}