-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinjector.spec.ts
130 lines (103 loc) · 2.94 KB
/
injector.spec.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
import { injectable, InjectKey, makeInjector, override } from './injector';
interface A {
foo: string;
}
// The following 3 injectables all provide an implementation of the "A" interface
const A = injectable<A>(() => {
return {
foo: 'a',
};
});
const A2 = injectable<A>(() => {
return {
foo: 'a2',
};
});
const A3 = injectable<A>(() => {
return {
foo: 'a3',
};
});
// Using a named interface for an injectable is nice, but not necessary - here's an example where TS
// just infers the InjectKey's type from the factory function's return value:
const B = injectable((inject) => {
const a = inject(A);
function getA(): A {
return a;
}
return {
getA,
bar: 'b' + a.foo,
};
});
// This demonstrates how to express an optional dependency - just use a key that defaults to undefined, and
// then override it in the injector if needed
const OptionalA = injectable<A | undefined>(() => undefined);
const C = injectable((inject) => {
const a = inject(A);
const b = inject(B);
const maybeA = inject(OptionalA);
return {
bagel: 'c' + a.foo + b.bar,
hasOptionalA: maybeA !== undefined,
};
});
// Type tests:
// @ts-expect-error Should only be able to override a key with a key/value assignable to it
override(A, injectable(() => ({ foo2: 'A' })));
class C1 {
private foo: undefined;
}
class C2 extends C1 {
private bar: undefined;
}
const IC1 = injectable(() => new C1());
const IC2 = injectable(() => new C2());
// @ts-expect-error Should not allow a subtype to be overridden with a parent type
override(IC2, IC1);
// @ts-expect-error Should properly type the InjectKey based on the return value of the factory fn
const BadReturnValue: InjectKey<string> = injectable(() => 1337);
// Behavior tests:
describe('injector v2', () => {
it('should work', () => {
const inject = makeInjector();
const c = inject(C);
const b = inject(B)
const a = inject(A);
expect(b.bar).toEqual('ba');
expect(c.bagel).toEqual('caba');
expect(b.getA()).toBe(a);
expect(c.hasOptionalA).toBe(false);
})
it('should allow overriding with key', () => {
const inject = makeInjector([
override(A, A2),
]);
const c = inject(C);
const b = inject(B)
const a = inject(A);
expect(a.foo).toEqual('a2');
expect(b.bar).toEqual('ba2');
expect(c.bagel).toEqual('ca2ba2');
expect(b.getA()).toBe(a);
})
it('should allow overriding with key (optional dep, for demonstration)', () => {
const inject = makeInjector([
override(OptionalA, A),
]);
const c = inject(C);
expect(c.hasOptionalA).toEqual(true);
})
it('should allow overriding with value', () => {
const inject = makeInjector([
override(A, injectable(() => ({ foo: 'A' }))),
]);
const c = inject(C);
const b = inject(B)
const a = inject(A);
expect(a.foo).toEqual('A');
expect(b.bar).toEqual('bA');
expect(c.bagel).toEqual('cAbA');
expect(b.getA()).toBe(a);
})
})