Last active
February 11, 2021 01:22
-
-
Save carmanchris31/6778dc94933ee4cbf86ce99f280afaca to your computer and use it in GitHub Desktop.
This file contains 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
// Inspired by https://medium.com/@magnusjt/ioc-container-in-nodejs-e7aea8a89600 | |
class UserModel { | |
isUser(): boolean { | |
return true | |
} | |
} | |
class UserService { | |
constructor(private model: UserModel) {} | |
doSomething(): void {} | |
} | |
class ContainerError extends Error { | |
name = 'ContainerError' | |
} | |
class Container<R extends Record<string, unknown> = {}> { | |
// @ts-expect-error | |
private factories: { [K in keyof R]: (instance: Container<R>) => R[K] } = {} | |
// @ts-expect-error | |
private resolved: { [K in keyof R]: R[K] } = {} | |
set<NewKey extends string, NewValue, NewRegistry extends Omit<R, NewKey> & Record<NewKey, NewValue>>(key: NewKey, factory: (instance: Container<R>) => NewValue): Container<NewRegistry> { | |
const newContainer = new Container<NewRegistry>() | |
// @ts-expect-error | |
newContainer.factories = { | |
...this.factories, | |
[key]: factory, | |
} | |
// @ts-expect-error | |
newContainer.resolved = { | |
...this.resolved, | |
[key]: undefined, | |
} | |
return newContainer | |
} | |
get<K extends keyof R>(key: K): R[K] { | |
if (this.resolved[key] === undefined) { | |
const resolved = this.factories[key](this) | |
if (resolved === undefined || resolved === null) { | |
throw new ContainerError(`Error building ${key}: received ${resolved}`) | |
} | |
this.resolved[key] = resolved | |
} | |
return this.resolved[key] | |
} | |
} | |
const container = new Container() | |
.set('SomeConstant', () => 4) | |
.set('SomeConstant', () => 'constant') | |
.set('UserModel', () => new UserModel()) | |
.set('UserService', (instance) => new UserService(instance.get('UserModel'))) | |
const model = container.get('UserModel'); | |
const service = container.get('UserService'); | |
const constant = container.get('SomeConstant'); | |
console.log(model, service, constant) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment