|
5 | 5 | * ;@lazy accessor value = lazy.of(() => getData()) |
6 | 6 | * } |
7 | 7 | */ |
8 | | -export function lazy<T, V>( |
9 | | - target: ClassAccessorDecoratorTarget<T, V>, |
10 | | - _context: ClassAccessorDecoratorContext<T, V>, |
11 | | -): ClassAccessorDecoratorResult<T, V> { |
12 | | - const { get, set } = target |
13 | | - let init = false |
| 8 | +export function lazy<C, T>( |
| 9 | + { get, set }: ClassAccessorDecoratorTarget<C, T>, |
| 10 | + { name, static: s }: ClassAccessorDecoratorContext<C, T>, |
| 11 | +): ClassAccessorDecoratorResult<C, T> { |
| 12 | + let init: ((C: C) => T) | undefined = function (C: C) { |
| 13 | + const f = get.call(C) as any as () => T |
| 14 | + if (!(initMap ||= new WeakSet()).has(f)) |
| 15 | + throw new Error( |
| 16 | + `Wrong usage of lazy decorator. Please write:\n @lazy${s ? ' static' : ''} accessor ${ |
| 17 | + typeof name === 'string' ? name : '[symbol]' |
| 18 | + } = lazy.mark(() => ...)`, |
| 19 | + ) |
| 20 | + const value = f() |
| 21 | + init = undefined |
| 22 | + set.call(C, value) |
| 23 | + return value |
| 24 | + } |
14 | 25 | return { |
15 | | - get() { |
16 | | - const val = get.call(this) |
17 | | - if (!init) { |
18 | | - if (typeof val !== 'function') throw new TypeError('Please use lazy.of(() => ...) to wrap the value.') |
19 | | - set.call(this, val()) |
20 | | - init = true |
21 | | - } |
22 | | - return val |
| 26 | + get(this: C) { |
| 27 | + init?.(this) |
| 28 | + return get.call(this) |
23 | 29 | }, |
24 | | - set(val) { |
25 | | - init ||= true |
| 30 | + set(this: C, val: T) { |
| 31 | + init?.(this) |
26 | 32 | set.call(this, val) |
27 | 33 | }, |
28 | 34 | } |
29 | 35 | } |
| 36 | +let initMap: WeakSet<object> |
30 | 37 | /** |
31 | 38 | * DO NOT use this function without the lazy decorator! It actually returning the init function instead of the value |
32 | 39 | * @param init The init function |
33 | 40 | */ |
34 | | -lazy.of = <T extends any>(init: () => T): T => init as any |
| 41 | +lazy.of = function <T>(init: (this: undefined) => T): T { |
| 42 | + const f = Reflect.apply(Function.bind, init, [undefined]) |
| 43 | + ;(initMap ||= new WeakSet()).add(f) |
| 44 | + return f |
| 45 | +} |
0 commit comments