Last active
October 16, 2023 13:36
-
-
Save lifeart/fbcc7bd8747562aa85d79b42ca991493 to your computer and use it in GitHub Desktop.
Lazy Services
This file contains hidden or 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
class Bar { | |
doSomething() { | |
console.log('do something'); | |
} | |
name: string; | |
} | |
type PromisifyProps<T> = { | |
[P in keyof T]: T[P] extends (...args: infer A) => infer R ? (...args: A) => Promise<R> : Promise<T[P]>; | |
}; | |
// a function to accept service load using import | |
// and it should return same type as service but all it's methods and properties should be promises | |
// we can use this function to make lazy loading of services | |
// under the hood we use proxy to make all methods and properties to be promises | |
function lazyService<T extends object>(service: () => Promise<T>): PromisifyProps<T> & { | |
toSync(): Promise<T>; | |
} { | |
let loadedService: T; | |
const proxy = new Proxy({}, { | |
get(_, prop) { | |
return new Promise(async (resolve, reject) => { | |
if (!loadedService) { | |
try { | |
loadedService = await service(); | |
} catch(e) { | |
reject(e); | |
} | |
} | |
if (prop === 'toSync') { | |
return resolve(loadedService); | |
} | |
const value = Reflect.get(loadedService, prop); | |
if (typeof value === 'function') { | |
return resolve((...args: any[]) => Promise.resolve(value.apply(loadedService, args))); | |
} else resolve(value); | |
}); | |
}, | |
}); | |
return proxy as PromisifyProps<T> & { | |
toSync(): Promise<T>; | |
} | |
} | |
class Foo { | |
bar = lazyService<Bar>(() => import('./bar')); | |
async onClick() { | |
// auto-load and invoke service method | |
await this.bar.doSomething(); | |
// get service property | |
const name = await this.bar.name; | |
// convert async service to sync (auto-load) | |
const sync = await this.bar.toSync(); | |
const secondName = sync.name; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment