-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathimpossible.ts
89 lines (77 loc) · 1.93 KB
/
impossible.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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
// Separates call and construct signatures of an object using proxies. #proxy
const fnKeys = [
"apply",
"arguments",
"bind",
"call",
"caller",
"length",
"name",
"prototype",
"toString",
] as const
const fnOwnProps = [
"arguments",
"caller",
"length",
"name",
"prototype",
] as const
function isFnKey(p: unknown): p is string {
return (fnKeys as any).indexOf(p) !== -1
}
export function addCallSignature<
T extends object,
S extends (this: any, ...args: any[]) => any,
>(
target: T,
signature: S,
): Exclude<
T,
((this: any, ...args: any[]) => any) | (abstract new (...args: any[]) => any)
> &
S {
return new Proxy(target, {
apply(_, thisArg, argArray) {
return Reflect.apply(signature, thisArg, argArray)
},
get(target, p, receiver) {
if (isFnKey(p)) return Reflect.get(signature, p, receiver)
return Reflect.get(target, p, receiver)
},
defineProperty(target, p, attributes) {
if (isFnKey(p)) return Reflect.defineProperty(signature, p, attributes)
return Reflect.defineProperty(target, p, attributes)
},
deleteProperty(target, p) {
if (isFnKey(p)) return Reflect.deleteProperty(signature, p)
return Reflect.deleteProperty(target, p)
},
getOwnPropertyDescriptor(target, p) {
if (isFnKey(p)) return Reflect.getOwnPropertyDescriptor(signature, p)
return Reflect.getOwnPropertyDescriptor(target, p)
},
has(target, p) {
if (isFnKey(p)) return Reflect.has(signature, p)
return Reflect.has(target, p)
},
ownKeys(target) {
const result = Reflect.ownKeys(target)
result.push(...fnOwnProps)
return result
},
set(target, p, value, receiver) {
if (isFnKey(p)) return Reflect.set(signature, p, value, receiver)
return Reflect.set(target, p, value, receiver)
},
}) as any
}
const d = addCallSignature(
{
a: 23,
b() {
return 45
},
},
() => 23,
)