diff --git a/src/Container.ts b/src/Container.ts index ba10659..a96d7c6 100644 --- a/src/Container.ts +++ b/src/Container.ts @@ -512,9 +512,12 @@ export class Container { ConcatInjectable(fn.token, () => this.providesService(fn).get(fn.token)) ) as Container; - private providesService[], Service>( - fn: InjectableFunction - ): Container> { + private providesService< + Token extends TokenType, + Tokens extends readonly ValidTokens[], + Service, + Dependencies, + >(fn: InjectableFunction): Container> { const token = fn.token; const dependencies: readonly any[] = fn.dependencies; // If the service depends on itself, e.g. in the multi-binding case, where we call append multiple times with diff --git a/src/Injectable.ts b/src/Injectable.ts index 01e5311..4d95894 100644 --- a/src/Injectable.ts +++ b/src/Injectable.ts @@ -105,33 +105,41 @@ export function Injectable( * * @example * ```ts - * class InjectableClassService { - * static dependencies = ["service"] as const; - * constructor(public service: string) {} - * public print(): string { - * console.log(this.service); - * } + * class Logger { + * static dependencies = ["config"] as const; + * constructor(private config: string) {} + * public print() { + * console.log(this.config); + * } * } * - * let container = Container.provides("service", "service value") - * .provides(ClassInjectable("classService", InjectableClassService)); - * - * container.get("classService").print(); // prints "service value" + * const container = Container + * .providesValue("config", "value") + * .provides(ClassInjectable("logger", Logger)); * - * // prefer using Container's provideClass method. Above is the equivalent of: - * container = Container.provides("service", "service value") - * .providesClass("classService", InjectableClassService); + * container.get("logger").print(); // prints "value" + * ``` * - * container.get("classService").print(); // prints "service value" + * It is recommended to use the `Container.provideClass()` method. The example above is equivalent to: + * ```ts + * const container = Container + * .providesValue("config", "value") + * .providesClass("logger", Logger); + * container.get("logger").print(); // prints "value" * ``` * * @param token Token identifying the Service. * @param cls InjectableClass to instantiate. */ -export function ClassInjectable( +export function ClassInjectable< + Class extends InjectableClass, + Dependencies extends ConstructorParameters, + Token extends TokenType, + Tokens extends Class["dependencies"], +>( token: Token, - cls: InjectableClass -): InjectableFunction; + cls: Class +): InjectableFunction, Tokens, Token, ConstructorReturnType>; export function ClassInjectable( token: TokenType, @@ -230,3 +238,5 @@ export function ConcatInjectable( factory.dependencies = [token, ...dependencies]; return factory; } + +export type ConstructorReturnType = T extends new (...args: any) => infer C ? C : any; diff --git a/src/PartialContainer.ts b/src/PartialContainer.ts index 8799eda..ab69297 100644 --- a/src/PartialContainer.ts +++ b/src/PartialContainer.ts @@ -1,6 +1,6 @@ import { entries } from "./entries"; -import { memoize } from "./memoize"; import type { Memoized } from "./memoize"; +import { memoize } from "./memoize"; import type { Container } from "./Container"; import type { AddService, @@ -10,10 +10,9 @@ import type { TokenType, ValidTokens, } from "./types"; +import type { ConstructorReturnType } from "./Injectable"; import { ClassInjectable, Injectable } from "./Injectable"; -type ConstructorReturnType = T extends new (...args: any) => infer C ? C : any; - // Using a conditional type forces TS language services to evaluate the type -- so when showing e.g. type hints, we // will see the mapped type instead of the AddDependencies type alias. This produces better hints. type AddDependencies = ParentDependencies extends any