Skip to content

Instantly share code, notes, and snippets.

@guiseek
Created May 18, 2024 05:16
Show Gist options
  • Save guiseek/c88cc10127413f69ac2df752a088e925 to your computer and use it in GitHub Desktop.
Save guiseek/c88cc10127413f69ac2df752a088e925 to your computer and use it in GitHub Desktop.
DI - use / add / set
const container = new Map()
const relations = new Map()
export const use = <T>(type: Key<T>): T => {
const concrete = container.get(type)
if (!concrete) throw `Provider ${type.name} não registrado`
return concrete
}
const provide = <T>({for: key, use}: For<T>) => {
const concrete = use ?? key
if (is.function<T>(concrete)) {
const deps = relations.get(key)
if (is.class<T>(concrete)) {
return new concrete(...deps)
}
return concrete(...deps)
}
return concrete as T
}
export function add<T>(provider: Type<T>): void
export function add<T>(provider: For<T>): void
export function add<T>(provider: Type<T> | For<T>) {
provider = 'for' in provider ? provider : {for: provider}
relations.set(provider.for, (provider.add ?? []).map(use))
const provided = provide(provider)
container.set(provider.for, provided)
}
export function set(...providers: For[]): void
export function set(...providers: Type[]): void
export function set(...providers: []) {
providers.map(add)
}
import type {Type} from './type'
export const is = {
function<R>(value: unknown): value is (...args: unknown[]) => R {
return typeof value === 'function'
},
class<T>(value: unknown): value is Type<T> {
return this.function(value) && 'prototype' in value
},
}
import {Type} from './type'
export class Token<T = unknown> {
constructor(public name: string | T) {}
}
export type Key<T> = Type<T> | Token<T>
export type Use<T> = T | Type<T>
export type For<T = unknown> = {
for: Key<T>
use?: Use<T>
add?: Key<T>[]
}
export interface Type<T = unknown> extends Function {
new (...params: any[]): T
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment