|
1 | 1 | /* eslint-disable @typescript-eslint/ban-types */
|
2 | 2 |
|
3 |
| -export type ContainerKey = string | symbol |
| 3 | +import { ContainerKey, ContextualParamsToResolverKeys } from './util.ts'; |
4 | 4 |
|
5 | 5 | type ExtractPrefix<S extends ContainerKey> =
|
6 | 6 | S extends `${infer Prefix}:${string}` ? Prefix : never
|
@@ -176,6 +176,51 @@ export interface WritableContainer<
|
176 | 176 | }
|
177 | 177 | >
|
178 | 178 |
|
| 179 | + /** |
| 180 | + * Registers a new constructor that might have asynchronous-resolvable |
| 181 | + * dependencies. This method is helpful when the constructor combinator is |
| 182 | + * not powerful enough (as it's only able to resolve synchronously). |
| 183 | + * |
| 184 | + * @param name The "name" of the dependency (can be a symbol). |
| 185 | + * @param constructor A class constructor, that will be use to resolve the |
| 186 | + * registered dependency. |
| 187 | + * @param args A list of dependency names that will be passed to the |
| 188 | + * registered constructor at construction time, when we try to |
| 189 | + * resolve the dependency. |
| 190 | + */ |
| 191 | + registerAsyncConstructor< |
| 192 | + TName extends ContainerKey, |
| 193 | + TParams extends readonly ( |
| 194 | + | TSyncDependencies[keyof TSyncDependencies] |
| 195 | + | TAsyncDependencies[keyof TAsyncDependencies] |
| 196 | + )[], |
| 197 | + TClass extends TName extends keyof TSyncDependencies |
| 198 | + ? never |
| 199 | + : TName extends keyof TAsyncDependencies |
| 200 | + ? TAsyncDependencies[TName] |
| 201 | + : unknown, |
| 202 | + TDependencies extends ContextualParamsToResolverKeys< |
| 203 | + TSyncDependencies, |
| 204 | + TAsyncDependencies, |
| 205 | + TParams |
| 206 | + >, |
| 207 | + >( |
| 208 | + name: TName, |
| 209 | + constructor: new (...args: TParams) => TClass, |
| 210 | + ...args: TDependencies |
| 211 | + ): Container< |
| 212 | + TSyncDependencies, |
| 213 | + { |
| 214 | + [TK in |
| 215 | + | keyof TAsyncDependencies |
| 216 | + | TName]: TK extends keyof TAsyncDependencies |
| 217 | + ? TName extends TK |
| 218 | + ? TClass |
| 219 | + : TAsyncDependencies[TK] |
| 220 | + : TClass |
| 221 | + } |
| 222 | + > |
| 223 | + |
179 | 224 | /**
|
180 | 225 | * Register an already instantiated dependency.
|
181 | 226 | *
|
@@ -367,6 +412,54 @@ function __createContainer<
|
367 | 412 | }
|
368 | 413 | },
|
369 | 414 |
|
| 415 | + registerAsyncConstructor< |
| 416 | + TName extends ContainerKey, |
| 417 | + TParams extends readonly ( |
| 418 | + | TSyncDependencies[keyof TSyncDependencies] |
| 419 | + | TAsyncDependencies[keyof TAsyncDependencies] |
| 420 | + )[], |
| 421 | + TClass extends TName extends keyof TSyncDependencies |
| 422 | + ? never |
| 423 | + : TName extends keyof TAsyncDependencies |
| 424 | + ? TAsyncDependencies[TName] |
| 425 | + : unknown, |
| 426 | + TDependencies extends ContextualParamsToResolverKeys< |
| 427 | + TSyncDependencies, |
| 428 | + TAsyncDependencies, |
| 429 | + TParams |
| 430 | + >, |
| 431 | + >( |
| 432 | + name: TName, |
| 433 | + constructor: new (...args: TParams) => TClass, |
| 434 | + ...args: TDependencies |
| 435 | + ): ContainerWithNewAsyncDep<TName, TClass> { |
| 436 | + const factory = async (container: typeof this) => { |
| 437 | + const argPromises = args.map((arg) => { |
| 438 | + return (arg as string) in syncDependencies |
| 439 | + ? container.resolve(arg as keyof TSyncDependencies) |
| 440 | + : container.resolveAsync(arg as keyof TAsyncDependencies) |
| 441 | + }) |
| 442 | + const resolvedParams = (await Promise.all( |
| 443 | + argPromises, |
| 444 | + )) as unknown as TParams |
| 445 | + |
| 446 | + return new constructor(...resolvedParams) |
| 447 | + } |
| 448 | + |
| 449 | + if (name in asyncDependencies) { |
| 450 | + return __createContainer(syncDependencies, { |
| 451 | + ...asyncDependencies, |
| 452 | + [name]: factory, |
| 453 | + }) as ContainerWithNewAsyncDep<TName, TClass> |
| 454 | + } else { |
| 455 | + ;(asyncDependencies as Record<TName, unknown>)[name] = factory |
| 456 | + return __createContainer( |
| 457 | + syncDependencies, |
| 458 | + asyncDependencies, |
| 459 | + ) as ContainerWithNewAsyncDep<TName, TClass> |
| 460 | + } |
| 461 | + }, |
| 462 | + |
370 | 463 | registerValue<TName extends ContainerKey, TDependency>(
|
371 | 464 | name: TName,
|
372 | 465 | dependency: TDependency,
|
|
0 commit comments