11import {
2- ContainerKey ,
2+ AsyncDependencyFactory ,
33 ReadableContainer ,
4+ ReadableSyncContainer ,
45 SyncDependencyFactory ,
56} from './container.ts' ;
6- import { ParamsToResolverKeys , TupleO , Zip } from './util.ts' ;
7+ import { ContainerKey , ParamsToResolverKeys , TupleO , Zip } from './util.ts' ;
78
89/**
910 * Given a dependency factory, returns a new factory that will always resolve
1011 * the same instance of the dependency.
1112 */
1213export function singleton <
1314 TVal ,
14- TDependencies extends Record < ContainerKey , unknown > ,
15+ TSyncDependencies extends Record < ContainerKey , unknown > ,
1516> (
16- // eslint-disable-next-line @typescript-eslint/ban-types
17- factory : SyncDependencyFactory < TVal , ReadableContainer < TDependencies , { } > > ,
18- // eslint-disable-next-line @typescript-eslint/ban-types
19- ) : SyncDependencyFactory < TVal , ReadableContainer < TDependencies , { } > > {
17+ factory : SyncDependencyFactory <
18+ TVal ,
19+ ReadableSyncContainer < TSyncDependencies >
20+ > ,
21+ ) : SyncDependencyFactory < TVal , ReadableSyncContainer < TSyncDependencies > > {
2022 let result : Awaited < TVal > | undefined
2123
2224 return ( container ) => {
@@ -27,6 +29,33 @@ export function singleton<
2729 }
2830}
2931
32+ /**
33+ * Given a dependency factory, returns a new asynchronous factory that will
34+ * always resolve the same instance of the dependency.
35+ */
36+ export function asyncSingleton <
37+ TVal ,
38+ TSyncDependencies extends Record < ContainerKey , unknown > ,
39+ TAsyncDependencies extends Record < ContainerKey , unknown > ,
40+ > (
41+ factory : AsyncDependencyFactory <
42+ TVal ,
43+ ReadableContainer < TSyncDependencies , TAsyncDependencies >
44+ > ,
45+ ) : AsyncDependencyFactory <
46+ TVal ,
47+ ReadableContainer < TSyncDependencies , TAsyncDependencies >
48+ > {
49+ let result : TVal | undefined
50+
51+ return async ( container ) => {
52+ if ( ! result ) {
53+ result = await factory ( container )
54+ }
55+ return result
56+ }
57+ }
58+
3059/**
3160 * Given a function, and a list of named dependencies, creates a new dependency
3261 * factory that will resolve a parameterless function wrapping the original
@@ -35,20 +64,20 @@ export function singleton<
3564export function func <
3665 TParams extends readonly unknown [ ] ,
3766 TReturn ,
38- TDependencies extends ParamsToResolverKeys < TParams > ,
67+ TSyncDependencies extends ParamsToResolverKeys < TParams > ,
3968> (
4069 fn : ( ...args : TParams ) => Awaited < TReturn > ,
41- ...args : TDependencies
70+ ...args : TSyncDependencies
4271) : SyncDependencyFactory <
4372 ( ) => TReturn ,
44- SyncFuncContainer < TParams , TDependencies >
73+ SyncFuncContainer < TParams , TSyncDependencies >
4574> {
46- return ( container : SyncFuncContainer < TParams , TDependencies > ) => {
75+ return ( container : SyncFuncContainer < TParams , TSyncDependencies > ) => {
4776 const resolvedArgs = args . map ( ( arg ) =>
4877 container . resolve (
4978 // This is ugly as hell, but I did not want to apply ts-ignore
5079 arg as Parameters <
51- SyncFuncContainer < TParams , TDependencies > [ 'resolve' ]
80+ SyncFuncContainer < TParams , TSyncDependencies > [ 'resolve' ]
5281 > [ 0 ] ,
5382 ) ,
5483 ) as unknown as TParams
@@ -89,11 +118,9 @@ export function constructor<
89118type SyncFuncContainer <
90119 TParams extends readonly unknown [ ] ,
91120 TSyncDependencies extends ParamsToResolverKeys < TParams > ,
92- > = ReadableContainer <
121+ > = ReadableSyncContainer <
93122 TupleO <
94123 // eslint-disable-next-line @typescript-eslint/no-explicit-any
95124 Extract < Zip < TSyncDependencies , TParams > , readonly [ ContainerKey , any ] [ ] >
96- > ,
97- // eslint-disable-next-line @typescript-eslint/ban-types
98- { }
125+ >
99126>
0 commit comments