1
1
import {
2
+ AsyncDependencyFactory ,
2
3
ContainerKey ,
3
4
ReadableContainer ,
5
+ ReadableSyncContainer ,
4
6
SyncDependencyFactory ,
5
7
} from './container.ts' ;
6
8
import { ParamsToResolverKeys , TupleO , Zip } from './util.ts' ;
@@ -11,12 +13,13 @@ import { ParamsToResolverKeys, TupleO, Zip } from './util.ts';
11
13
*/
12
14
export function singleton <
13
15
TVal ,
14
- TDependencies extends Record < ContainerKey , unknown > ,
16
+ TSyncDependencies extends Record < ContainerKey , unknown > ,
15
17
> (
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 > > {
20
23
let result : Awaited < TVal > | undefined
21
24
22
25
return ( container ) => {
@@ -27,6 +30,33 @@ export function singleton<
27
30
}
28
31
}
29
32
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
+
30
60
/**
31
61
* Given a function, and a list of named dependencies, creates a new dependency
32
62
* factory that will resolve a parameterless function wrapping the original
@@ -35,20 +65,20 @@ export function singleton<
35
65
export function func <
36
66
TParams extends readonly unknown [ ] ,
37
67
TReturn ,
38
- TDependencies extends ParamsToResolverKeys < TParams > ,
68
+ TSyncDependencies extends ParamsToResolverKeys < TParams > ,
39
69
> (
40
70
fn : ( ...args : TParams ) => Awaited < TReturn > ,
41
- ...args : TDependencies
71
+ ...args : TSyncDependencies
42
72
) : SyncDependencyFactory <
43
73
( ) => TReturn ,
44
- SyncFuncContainer < TParams , TDependencies >
74
+ SyncFuncContainer < TParams , TSyncDependencies >
45
75
> {
46
- return ( container : SyncFuncContainer < TParams , TDependencies > ) => {
76
+ return ( container : SyncFuncContainer < TParams , TSyncDependencies > ) => {
47
77
const resolvedArgs = args . map ( ( arg ) =>
48
78
container . resolve (
49
79
// This is ugly as hell, but I did not want to apply ts-ignore
50
80
arg as Parameters <
51
- SyncFuncContainer < TParams , TDependencies > [ 'resolve' ]
81
+ SyncFuncContainer < TParams , TSyncDependencies > [ 'resolve' ]
52
82
> [ 0 ] ,
53
83
) ,
54
84
) as unknown as TParams
@@ -89,11 +119,9 @@ export function constructor<
89
119
type SyncFuncContainer <
90
120
TParams extends readonly unknown [ ] ,
91
121
TSyncDependencies extends ParamsToResolverKeys < TParams > ,
92
- > = ReadableContainer <
122
+ > = ReadableSyncContainer <
93
123
TupleO <
94
124
// eslint-disable-next-line @typescript-eslint/no-explicit-any
95
125
Extract < Zip < TSyncDependencies , TParams > , readonly [ ContainerKey , any ] [ ] >
96
- > ,
97
- // eslint-disable-next-line @typescript-eslint/ban-types
98
- { }
126
+ >
99
127
>
0 commit comments