feat(core): more precise type for `APP_INITIALIZER` token (#40986)

This commit updates the type of the `APP_INITIALIZER` injection token to
better document the expected types of values that Angular handles. Only
Promises and Observables are awaited and other types of values are ignored,
so the type of `APP_INITIALIZER` has been updated to
`Promise<unknown> | Observable<unknown> | void` to reflect this behavior.

BREAKING CHANGE:

The type of the `APP_INITIALIZER` token has been changed to more accurately
reflect the types of return values that are handled by Angular. Previously,
each initializer callback was typed to return `any`, this is now
`Promise<unknown> | Observable<unknown> | void`. In the unlikely event that
your application uses the `Injector.get` or `TestBed.inject` API to inject
the `APP_INITIALIZER` token, you may need to update the code to account for
the stricter type.

Additionally, TypeScript may report the TS2742 error if the `APP_INITIALIZER`
token is used in an expression of which its inferred type has to be emitted
into a .d.ts file. To workaround this, an explicit type annotation is needed,
which would typically be `Provider` or `Provider[]`.

Closes #40729

PR Close #40986
This commit is contained in:
abarghoud 2021-02-24 20:29:09 +01:00 committed by Andrew Kushnir
parent bf158e7ff0
commit ca721c2972
3 changed files with 9 additions and 5 deletions

View File

@ -25,12 +25,12 @@ export declare const APP_BOOTSTRAP_LISTENER: InjectionToken<((compRef: Component
export declare const APP_ID: InjectionToken<string>;
export declare const APP_INITIALIZER: InjectionToken<(() => void)[]>;
export declare const APP_INITIALIZER: InjectionToken<readonly (() => Observable<unknown> | Promise<unknown> | void)[]>;
export declare class ApplicationInitStatus {
readonly done = false;
readonly donePromise: Promise<any>;
constructor(appInits: (() => any)[]);
constructor(appInits: ReadonlyArray<() => Observable<unknown> | Promise<unknown> | void>);
}
export declare class ApplicationModule {

View File

@ -6,6 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Observable} from 'rxjs';
import {Inject, Injectable, InjectionToken, Optional} from './di';
import {isObservable, isPromise} from './util/lang';
import {noop} from './util/noop';
@ -28,7 +29,9 @@ import {noop} from './util/noop';
*
* @publicApi
*/
export const APP_INITIALIZER = new InjectionToken<Array<() => void>>('Application Initializer');
export const APP_INITIALIZER =
new InjectionToken<ReadonlyArray<() => Observable<unknown>| Promise<unknown>| void>>(
'Application Initializer');
/**
* A class that reflects the state of running {@link APP_INITIALIZER} functions.
@ -43,7 +46,8 @@ export class ApplicationInitStatus {
public readonly donePromise: Promise<any>;
public readonly done = false;
constructor(@Inject(APP_INITIALIZER) @Optional() private appInits: (() => any)[]) {
constructor(@Inject(APP_INITIALIZER) @Optional() private readonly appInits:
ReadonlyArray<() => Observable<unknown>| Promise<unknown>| void>) {
this.donePromise = new Promise((res, rej) => {
this.resolve = res;
this.reject = rej;

View File

@ -584,7 +584,7 @@ export function getBootstrapListener(r: RouterInitializer) {
export const ROUTER_INITIALIZER =
new InjectionToken<(compRef: ComponentRef<any>) => void>('Router Initializer');
export function provideRouterInitializer() {
export function provideRouterInitializer(): ReadonlyArray<Provider> {
return [
RouterInitializer,
{