From 12b4ec3d85e9136c8df6597c7cdbb4df8d30178a Mon Sep 17 00:00:00 2001 From: Pawel Kozlowski Date: Fri, 27 May 2022 13:52:34 +0200 Subject: [PATCH] docs: create a dedicated page for the NG0203 error (#46166) Adds a dedicated error page for NG0203 (injection context). PR Close #46166 --- aio/content/errors/NG0203.md | 83 +++++++++++++++++++++++++++++++ goldens/public-api/core/errors.md | 2 +- packages/core/src/errors.ts | 2 +- 3 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 aio/content/errors/NG0203.md diff --git a/aio/content/errors/NG0203.md b/aio/content/errors/NG0203.md new file mode 100644 index 00000000000..28381daff90 --- /dev/null +++ b/aio/content/errors/NG0203.md @@ -0,0 +1,83 @@ +@name `inject()` must be called from an injection context +@category runtime +@shortDescription `inject()` must be called from an injection context (a constructor, a factory function or a field initializer) + +@description +You see this error when you try to use the `inject()` function outside of the allowed injection context. The injection context is available during the class creation and initialization. + +In practice the `inject()` calls are allowed in a constructor, a constructor parameter and a field initializer: + +```typescript +@Injectable({providedIn: 'root'}) +export class Car { + radio: Radio|undefined; + + // OK: field initializer + spareTyre = inject(Tyre); + + // OK: constructor parameter + constructor(readonly engine: Engine = inject(Engine)) { + + // OK: constructor body + this.radio = inject(Radio); + } +} +``` + +It is also legal to call `inject` from a provider's factory: + +```typescript +providers: [ + {provide: Car, useFactory: () => { + // OK: a class factory + const engine = inject(Engine); + return new Car(engine); + }} +] +``` + +The `inject()` calls might be wrapped in an intermediate function and will work correctly as long as a wrapper function is used in one of the allowed contexts: + +```typescript +function getAndLog(token: ProviderToken): T { + const instance = inject(token); + + console.log('Getting', token.toString()); + + return instance; +} + +@Injectable({providedIn: 'root'}) +export class Car { + constructor(readonly engine: Engine = getAndLog(Engine)) { + } +} +``` + +Calls to the `inject()` function outside of the class creation context will result in error. Most notably, calls to `inject()` are disallowed after a class instance was created, in methods: + +```typescript +@Injectable({providedIn: 'root'}) +export class Car { + + start() { + // ERROR: too late, the Car instance was already created and fully initialized + const engine = inject(Engine); + engine.start(); + } +} +``` + +@debugging + +Work backwards from the stack trace of the error to identify a place where the disallowed call to `inject()` is located. + +To fix the error move the `inject()` call to an allowed place (usually a class constructor or a field initializer). + + + + + + + +@reviewed 2022-05-27 diff --git a/goldens/public-api/core/errors.md b/goldens/public-api/core/errors.md index 2c17180ab18..64c8c631d65 100644 --- a/goldens/public-api/core/errors.md +++ b/goldens/public-api/core/errors.md @@ -49,7 +49,7 @@ export const enum RuntimeErrorCode { // (undocumented) MISSING_GENERATED_DEF = 906, // (undocumented) - MISSING_INJECTION_CONTEXT = 203, + MISSING_INJECTION_CONTEXT = -203, // (undocumented) MULTIPLE_COMPONENTS_MATCH = -300, // (undocumented) diff --git a/packages/core/src/errors.ts b/packages/core/src/errors.ts index 4652ef1ae5d..c2b45cb1532 100644 --- a/packages/core/src/errors.ts +++ b/packages/core/src/errors.ts @@ -27,7 +27,7 @@ export const enum RuntimeErrorCode { CYCLIC_DI_DEPENDENCY = -200, PROVIDER_NOT_FOUND = -201, INVALID_FACTORY_DEPENDENCY = 202, - MISSING_INJECTION_CONTEXT = 203, + MISSING_INJECTION_CONTEXT = -203, INVALID_INJECTION_TOKEN = 204, INJECTOR_ALREADY_DESTROYED = 205, PROVIDER_IN_WRONG_CONTEXT = 207,