Skip to content
This repository was archived by the owner on Apr 21, 2024. It is now read-only.

Commit 793e533

Browse files
authored
Merge pull request #8 from Coder-Spirit/async-combinators
Async combinators
2 parents 77c3a43 + 8970650 commit 793e533

14 files changed

+1073
-637
lines changed

README.md

+24-26
Original file line numberDiff line numberDiff line change
@@ -33,28 +33,6 @@ import { ... } from 'https://denopkg.com/Coder-Spirit/lambda-ioc@[VERSION]/lambd
3333
import { ... } from 'https://deno.land/x/lambda_ioc@[VERSION]/lambda-ioc/deno/index.ts'
3434
```
3535

36-
## Benefits
37-
38-
- 100% type safe:
39-
- The type checker will complain if we try to resolve unregistered
40-
dependencies.
41-
- The type checker will complain if we try to register new dependencies that
42-
depend on unregistered dependencies, or if there is any kind of type
43-
mismatch.
44-
- Purely functional
45-
- Immutable
46-
- Circular dependencies are impossible
47-
48-
## Drawbacks
49-
50-
- All dependencies must be declared "in order".
51-
- This implies that this IoC container cannot be used in combination with some
52-
auto-wiring solutions, such as IoC decorators.
53-
- The involved types are a bit convoluted:
54-
- They might cause the type checker to be slow.
55-
- In some situations, the type checker might be unable to infer the involved
56-
types due to excessive "nested types" depth.
57-
5836
## Example
5937

6038
```ts
@@ -105,13 +83,33 @@ container.resolveGroup('group2') // ~ [3, 4], not necessarily in the same order
10583
```
10684

10785
It is also possible to register and resolve asynchronous factories and
108-
dependencies. They are not documented yet because some "helpers" are missing,
109-
and therefore it's a bit more annoying to take advantage of that feature.
110-
111-
If you are curious, just try out:
86+
dependencies. If you are curious, just try out:
11287
- `registerAsync`
88+
- `registerAsyncConstructor`
11389
- `resolveAsync`
11490

91+
## Benefits
92+
93+
- 100% type safe:
94+
- The type checker will complain if we try to resolve unregistered
95+
dependencies.
96+
- The type checker will complain if we try to register new dependencies that
97+
depend on unregistered dependencies, or if there is any kind of type
98+
mismatch.
99+
- Purely functional
100+
- Immutable
101+
- Circular dependencies are impossible
102+
103+
## Drawbacks
104+
105+
- All dependencies must be declared "in order".
106+
- This implies that this IoC container cannot be used in combination with some
107+
auto-wiring solutions, such as IoC decorators.
108+
- The involved types are a bit convoluted:
109+
- They might cause the type checker to be slow.
110+
- In some situations, the type checker might be unable to infer the involved
111+
types due to excessive "nested types" depth.
112+
115113
## Differences respect to Diddly
116114

117115
- First-class support for Deno.

lambda-ioc/README.md

+24-26
Original file line numberDiff line numberDiff line change
@@ -33,28 +33,6 @@ import { ... } from 'https://denopkg.com/Coder-Spirit/lambda-ioc@[VERSION]/lambd
3333
import { ... } from 'https://deno.land/x/lambda_ioc@[VERSION]/lambda-ioc/deno/index.ts'
3434
```
3535

36-
## Benefits
37-
38-
- 100% type safe:
39-
- The type checker will complain if we try to resolve unregistered
40-
dependencies.
41-
- The type checker will complain if we try to register new dependencies that
42-
depend on unregistered dependencies, or if there is any kind of type
43-
mismatch.
44-
- Purely functional
45-
- Immutable
46-
- Circular dependencies are impossible
47-
48-
## Drawbacks
49-
50-
- All dependencies must be declared "in order".
51-
- This implies that this IoC container cannot be used in combination with some
52-
auto-wiring solutions, such as IoC decorators.
53-
- The involved types are a bit convoluted:
54-
- They might cause the type checker to be slow.
55-
- In some situations, the type checker might be unable to infer the involved
56-
types due to excessive "nested types" depth.
57-
5836
## Example
5937

6038
```ts
@@ -105,13 +83,33 @@ container.resolveGroup('group2') // ~ [3, 4], not necessarily in the same order
10583
```
10684

10785
It is also possible to register and resolve asynchronous factories and
108-
dependencies. They are not documented yet because some "helpers" are missing,
109-
and therefore it's a bit more annoying to take advantage of that feature.
110-
111-
If you are curious, just try out:
86+
dependencies. If you are curious, just try out:
11287
- `registerAsync`
88+
- `registerAsyncConstructor`
11389
- `resolveAsync`
11490

91+
## Benefits
92+
93+
- 100% type safe:
94+
- The type checker will complain if we try to resolve unregistered
95+
dependencies.
96+
- The type checker will complain if we try to register new dependencies that
97+
depend on unregistered dependencies, or if there is any kind of type
98+
mismatch.
99+
- Purely functional
100+
- Immutable
101+
- Circular dependencies are impossible
102+
103+
## Drawbacks
104+
105+
- All dependencies must be declared "in order".
106+
- This implies that this IoC container cannot be used in combination with some
107+
auto-wiring solutions, such as IoC decorators.
108+
- The involved types are a bit convoluted:
109+
- They might cause the type checker to be slow.
110+
- In some situations, the type checker might be unable to infer the involved
111+
types due to excessive "nested types" depth.
112+
115113
## Differences respect to Diddly
116114

117115
- First-class support for Deno.

lambda-ioc/deno/combinators.ts

+43-16
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,24 @@
11
import {
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
*/
1213
export 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<
3564
export 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<
89118
type 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

Comments
 (0)