11import {
2+ AsyncDependencyFactory ,
23 ContainerKey ,
34 ReadableContainer ,
5+ ReadableSyncContainer ,
46 SyncDependencyFactory ,
57} from './container.ts' ;
68import { ParamsToResolverKeys , TupleO , Zip } from './util.ts' ;
@@ -11,12 +13,13 @@ import { ParamsToResolverKeys, TupleO, Zip } from './util.ts';
1113 */
1214export function singleton <
1315 TVal ,
14- TDependencies extends Record < ContainerKey , unknown > ,
16+ TSyncDependencies extends Record < ContainerKey , unknown > ,
1517> (
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 , { } > > {
18+ factory : SyncDependencyFactory <
19+ TVal ,
20+ ReadableSyncContainer < TSyncDependencies >
21+ > ,
22+ ) : SyncDependencyFactory < TVal , ReadableSyncContainer < TSyncDependencies > > {
2023 let result : Awaited < TVal > | undefined
2124
2225 return ( container ) => {
@@ -27,6 +30,33 @@ export function singleton<
2730 }
2831}
2932
33+ /**
34+ * Given a dependency factory, returns a new asynchronous factory that will
35+ * always resolve the same instance of the dependency.
36+ */
37+ export function asyncSingleton <
38+ TVal ,
39+ TSyncDependencies extends Record < ContainerKey , unknown > ,
40+ TAsyncDependencies extends Record < ContainerKey , unknown > ,
41+ > (
42+ factory : AsyncDependencyFactory <
43+ TVal ,
44+ ReadableContainer < TSyncDependencies , TAsyncDependencies >
45+ > ,
46+ ) : AsyncDependencyFactory <
47+ TVal ,
48+ ReadableContainer < TSyncDependencies , TAsyncDependencies >
49+ > {
50+ let result : TVal | undefined
51+
52+ return async ( container ) => {
53+ if ( ! result ) {
54+ result = await factory ( container )
55+ }
56+ return result
57+ }
58+ }
59+
3060/**
3161 * Given a function, and a list of named dependencies, creates a new dependency
3262 * factory that will resolve a parameterless function wrapping the original
@@ -35,20 +65,20 @@ export function singleton<
3565export function func <
3666 TParams extends readonly unknown [ ] ,
3767 TReturn ,
38- TDependencies extends ParamsToResolverKeys < TParams > ,
68+ TSyncDependencies extends ParamsToResolverKeys < TParams > ,
3969> (
4070 fn : ( ...args : TParams ) => Awaited < TReturn > ,
41- ...args : TDependencies
71+ ...args : TSyncDependencies
4272) : SyncDependencyFactory <
4373 ( ) => TReturn ,
44- SyncFuncContainer < TParams , TDependencies >
74+ SyncFuncContainer < TParams , TSyncDependencies >
4575> {
46- return ( container : SyncFuncContainer < TParams , TDependencies > ) => {
76+ return ( container : SyncFuncContainer < TParams , TSyncDependencies > ) => {
4777 const resolvedArgs = args . map ( ( arg ) =>
4878 container . resolve (
4979 // This is ugly as hell, but I did not want to apply ts-ignore
5080 arg as Parameters <
51- SyncFuncContainer < TParams , TDependencies > [ 'resolve' ]
81+ SyncFuncContainer < TParams , TSyncDependencies > [ 'resolve' ]
5282 > [ 0 ] ,
5383 ) ,
5484 ) as unknown as TParams
@@ -89,11 +119,9 @@ export function constructor<
89119type SyncFuncContainer <
90120 TParams extends readonly unknown [ ] ,
91121 TSyncDependencies extends ParamsToResolverKeys < TParams > ,
92- > = ReadableContainer <
122+ > = ReadableSyncContainer <
93123 TupleO <
94124 // eslint-disable-next-line @typescript-eslint/no-explicit-any
95125 Extract < Zip < TSyncDependencies , TParams > , readonly [ ContainerKey , any ] [ ] >
96- > ,
97- // eslint-disable-next-line @typescript-eslint/ban-types
98- { }
126+ >
99127>
0 commit comments