From ff84c7360334792a9a422bd0fa0353e0cf670525 Mon Sep 17 00:00:00 2001 From: Andrew Scott Date: Mon, 28 Nov 2022 14:43:18 -0800 Subject: [PATCH] docs(core): Document invalid multi token (#48267) Add error page for invalid multi token runtime error PR Close #48267 --- aio/content/errors/NG0209.md | 17 +++++++++++++++++ goldens/public-api/core/errors.md | 2 +- packages/core/src/application_init.ts | 1 + packages/core/src/application_ref.ts | 12 ++++++++++-- packages/core/src/errors.ts | 2 +- .../acceptance/environment_injector_spec.ts | 7 ++----- 6 files changed, 32 insertions(+), 9 deletions(-) create mode 100644 aio/content/errors/NG0209.md diff --git a/aio/content/errors/NG0209.md b/aio/content/errors/NG0209.md new file mode 100644 index 00000000000..f9d2593fd56 --- /dev/null +++ b/aio/content/errors/NG0209.md @@ -0,0 +1,17 @@ +@name Invalid multi provider +@category runtime +@shortDescription Expected provider to be `multi: true` but did not get an Array + +@description + +The Angular runtime will throw this error when it injects a token intended to be used with `multi: true` but +a non-Array was found instead. For example, `ENVIRONMENT_INITIALIZER` should be provided +like `{provide: ENVIRONMENT_INITIALIZER, multi: true, useValue: () => {...}}`. + + + + + + + +@reviewed 2022-11-28 \ No newline at end of file diff --git a/goldens/public-api/core/errors.md b/goldens/public-api/core/errors.md index 65712aab89c..be27a49c234 100644 --- a/goldens/public-api/core/errors.md +++ b/goldens/public-api/core/errors.md @@ -59,7 +59,7 @@ export const enum RuntimeErrorCode { // (undocumented) INVALID_INJECTION_TOKEN = 204, // (undocumented) - INVALID_MULTI_PROVIDER = 209, + INVALID_MULTI_PROVIDER = -209, // (undocumented) MISSING_GENERATED_DEF = 906, // (undocumented) diff --git a/packages/core/src/application_init.ts b/packages/core/src/application_init.ts index 418de8832f1..efa0a813594 100644 --- a/packages/core/src/application_init.ts +++ b/packages/core/src/application_init.ts @@ -102,6 +102,7 @@ export class ApplicationInitStatus { constructor(@Inject(APP_INITIALIZER) @Optional() private readonly appInits: ReadonlyArray<() => Observable| Promise| void>) { + // TODO: Throw RuntimeErrorCode.INVALID_MULTI_PROVIDER if appInits is not an array this.donePromise = new Promise((res, rej) => { this.resolve = res; this.reject = rej; diff --git a/packages/core/src/application_ref.ts b/packages/core/src/application_ref.ts index a16e2107d5c..cc2009a7d0f 100644 --- a/packages/core/src/application_ref.ts +++ b/packages/core/src/application_ref.ts @@ -1051,8 +1051,16 @@ export class ApplicationRef { this.tick(); this.components.push(componentRef); // Get the listeners lazily to prevent DI cycles. - const listeners = - this._injector.get(APP_BOOTSTRAP_LISTENER, []).concat(this._bootstrapListeners); + const listeners = this._injector.get(APP_BOOTSTRAP_LISTENER, []); + if (ngDevMode && !Array.isArray(listeners)) { + throw new RuntimeError( + RuntimeErrorCode.INVALID_MULTI_PROVIDER, + 'Unexpected type of the `APP_BOOTSTRAP_LISTENER` token value ' + + `(expected an array, but got ${typeof listeners}). ` + + 'Please check that the `APP_BOOTSTRAP_LISTENER` token is configured as a ' + + '`multi: true` provider.'); + } + listeners.push(...this._bootstrapListeners); listeners.forEach((listener) => listener(componentRef)); } diff --git a/packages/core/src/errors.ts b/packages/core/src/errors.ts index 00f9f77ac56..082fbce572c 100644 --- a/packages/core/src/errors.ts +++ b/packages/core/src/errors.ts @@ -32,7 +32,7 @@ export const enum RuntimeErrorCode { INJECTOR_ALREADY_DESTROYED = 205, PROVIDER_IN_WRONG_CONTEXT = 207, MISSING_INJECTION_TOKEN = 208, - INVALID_MULTI_PROVIDER = 209, + INVALID_MULTI_PROVIDER = -209, // Template Errors MULTIPLE_COMPONENTS_MATCH = -300, diff --git a/packages/core/test/acceptance/environment_injector_spec.ts b/packages/core/test/acceptance/environment_injector_spec.ts index 03ee4a23620..981bd3699a1 100644 --- a/packages/core/test/acceptance/environment_injector_spec.ts +++ b/packages/core/test/acceptance/environment_injector_spec.ts @@ -8,6 +8,7 @@ import {Component, ComponentFactoryResolver, createEnvironmentInjector, ENVIRONMENT_INITIALIZER, EnvironmentInjector, inject, InjectFlags, InjectionToken, INJECTOR, Injector, NgModuleRef, ViewContainerRef} from '@angular/core'; import {R3Injector} from '@angular/core/src/di/r3_injector'; +import {RuntimeError, RuntimeErrorCode} from '@angular/core/src/errors'; import {TestBed} from '@angular/core/testing'; describe('environment injector', () => { @@ -117,11 +118,7 @@ describe('environment injector', () => { useValue: () => {}, }]; expect(() => createEnvironmentInjector(providers, parentEnvInjector)) - .toThrowError( - 'NG0209: Unexpected type of the `ENVIRONMENT_INITIALIZER` token value ' + - '(expected an array, but got function). ' + - 'Please check that the `ENVIRONMENT_INITIALIZER` token is configured as ' + - 'a `multi: true` provider.'); + .toThrowMatching((e: RuntimeError) => e.code === RuntimeErrorCode.INVALID_MULTI_PROVIDER); }); it('should adopt environment-scoped providers', () => {