Skip to content

Commit

Permalink
docs: add note about inheritance and tree-shaking
Browse files Browse the repository at this point in the history
  • Loading branch information
dirkluijk committed Sep 29, 2024
1 parent 7861d8b commit f2212ca
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 27 deletions.
23 changes: 13 additions & 10 deletions docs/advanced/inheritance.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,22 +36,25 @@ const myServices = container.get(ExampleService, { multi: true });
// and will be the same instances as "fooService" and "barService'
```

> [!IMPORTANT]
> Make sure your subclasses are imported somewhere. Otherwise, the auto-binding might not work since their
> decorators are not invoked. Even worse, your subclasses might not even appear in your final bundle due to
> [tree-shaking](/advanced/tree-shaking).
>
> To prevent this, consider to register your subclasses explicitly:
>
> ```typescript
> container.bindAll(FooService, BarService);
> ```
## Manual binding
Under the hood, the example above would be the same as:
```typescript
container.bindAll(
{
provide: FooService,
useClass: FooService,
multi: true,
},
{
provide: BarService,
useClass: BarService,
multi: true,
},
FooService,
BarService,
{
provide: MyAbstractService,
useExisting: FooService,
Expand Down
34 changes: 17 additions & 17 deletions src/container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
isAsyncFactoryProvider,
isMultiProvider,
isExistingProvider,
existingProviderAlreadyDefined,
} from "./providers.js";
import { getInjectableTargets, isInjectable } from "./decorators.js";
import { assertPresent } from "./utils.js";
Expand All @@ -19,26 +20,21 @@ export class Container {
public bindAll<A>(p1: Provider<A>): this;
public bindAll<A, B>(p1: Provider<A>, p2: Provider<B>): this;
public bindAll<A, B, C>(p1: Provider<A>, p2: Provider<B>, p3: Provider<C>): this;
public bindAll<A, B, C, D>(
p1: Provider<A>,
p2: Provider<B>,
p3: Provider<C>,
p4: Provider<D>
): this;
public bindAll<A, B, C, D>(p1: Provider<A>, p2: Provider<B>, p3: Provider<C>, p4: Provider<D>): this;
public bindAll<A, B, C, D, E>(
p1: Provider<A>,
p2: Provider<B>,
p3: Provider<C>,
p4: Provider<D>,
p5: Provider<E>
p5: Provider<E>,
): this;
public bindAll<A, B, C, D, E, F>(
p1: Provider<A>,
p2: Provider<B>,
p3: Provider<C>,
p4: Provider<D>,
p5: Provider<E>,
p6: Provider<F>
p6: Provider<F>,
): this;
public bindAll<A, B, C, D, E, F, G>(
p1: Provider<A>,
Expand All @@ -47,7 +43,7 @@ export class Container {
p4: Provider<D>,
p5: Provider<E>,
p6: Provider<F>,
p7: Provider<G>
p7: Provider<G>,
): this;
public bindAll<A, B, C, D, E, F, G, H>(
p1: Provider<A>,
Expand All @@ -57,7 +53,7 @@ export class Container {
p5: Provider<E>,
p6: Provider<F>,
p7: Provider<G>,
p8: Provider<H>
p8: Provider<H>,
): this;
public bindAll<A, B, C, D, E, F, G, H, I>(
p1: Provider<A>,
Expand All @@ -68,7 +64,7 @@ export class Container {
p6: Provider<F>,
p7: Provider<G>,
p8: Provider<H>,
p9: Provider<I>
p9: Provider<I>,
): this;
public bindAll<A, B, C, D, E, F, G, H, I>(
p1: Provider<A>,
Expand Down Expand Up @@ -285,13 +281,17 @@ export class Container {
),
];

immediateSubclasses.forEach((immediateSubClass) => {
this.bind({
provide: token,
useExisting: immediateSubClass,
multi: true,
const existingProviders = this.providers.get(token) ?? [];

immediateSubclasses
.filter((subClass) => !existingProviderAlreadyDefined(subClass, existingProviders))
.forEach((subClass) => {
this.bind({
provide: token,
useExisting: subClass,
multi: true,
});
});
});
} else if (!this.providers.has(token) && isInjectionToken(token) && token.options?.factory) {
const async = token.options.async;
if (!async) {
Expand Down
4 changes: 4 additions & 0 deletions src/providers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,7 @@ export function isExistingProvider<T>(provider: Provider<T>): provider is Existi
export function isMultiProvider<T>(provider: Provider<T>): boolean {
return "provide" in provider && "multi" in provider && provider.multi === true;
}

export function existingProviderAlreadyDefined(token: Token<unknown>, providers: Provider<unknown>[]) {
return providers.some(it => isExistingProvider(it) && (it.useExisting === token || it.provide === token));
}

0 comments on commit f2212ca

Please sign in to comment.