refactor(ivy): make return value of define(Component|Directive|Pipe|Injector|Injectable) private (#23371) (#23383)
Ivy definition looks something like this: ``` class MyService { static ngInjectableDef = defineInjectable({ … }); } ``` Here the argument to `defineInjectable` is well known public contract which needs to be honored in backward compatible way between versions. The type of the return value of `defineInjectable` on the other hand is private and can change shape drastically between versions without effecting backwards compatibility of libraries publish to NPM. To our users it is effectively an opaque token. For this reson why declare the return value of `defineInjectable` as `never`. PR Close #23383
This commit is contained in:
@ -20,9 +20,7 @@ import {ClassProvider, ClassSansProvider, ConstructorProvider, ConstructorSansPr
|
||||
* `InjectorDef`, `NgModule`, or a special scope (e.g. `'root'`). A value of `null` indicates
|
||||
* that the injectable does not belong to any scope.
|
||||
*
|
||||
* This type is typically generated by the Angular compiler, but can be hand-written if needed.
|
||||
*
|
||||
* @experimental
|
||||
* NOTE: This is a private type and should not be exported
|
||||
*/
|
||||
export interface InjectableDef<T> {
|
||||
/**
|
||||
@ -54,7 +52,7 @@ export interface InjectableDef<T> {
|
||||
* structure of providers with a defined priority (identically to how `NgModule`s also have
|
||||
* an import/dependency structure).
|
||||
*
|
||||
* @experimental
|
||||
* NOTE: This is a private type and should not be exported
|
||||
*/
|
||||
export interface InjectorDef<T> {
|
||||
factory: () => T;
|
||||
@ -75,7 +73,12 @@ export interface InjectorDef<T> {
|
||||
*
|
||||
* @experimental
|
||||
*/
|
||||
export interface InjectableType<T> extends Type<T> { ngInjectableDef: InjectableDef<T>; }
|
||||
export interface InjectableType<T> extends Type<T> {
|
||||
/**
|
||||
* Opaque type whose structure is highly version dependent. Do not rely on any properties.
|
||||
*/
|
||||
ngInjectableDef: never;
|
||||
}
|
||||
|
||||
/**
|
||||
* A type which has an `InjectorDef` static field.
|
||||
@ -84,7 +87,12 @@ export interface InjectableType<T> extends Type<T> { ngInjectableDef: Injectable
|
||||
*
|
||||
* @experimental
|
||||
*/
|
||||
export interface InjectorType<T> extends Type<T> { ngInjectorDef: InjectorDef<T>; }
|
||||
export interface InjectorType<T> extends Type<T> {
|
||||
/**
|
||||
* Opaque type whose structure is highly version dependent. Do not rely on any properties.
|
||||
*/
|
||||
ngInjectorDef: never;
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes the `InjectorDef` equivalent of a `ModuleWithProviders`, an `InjectorDefType` with an
|
||||
@ -92,7 +100,7 @@ export interface InjectorType<T> extends Type<T> { ngInjectorDef: InjectorDef<T>
|
||||
*
|
||||
* Objects of this type can be listed in the imports section of an `InjectorDef`.
|
||||
*
|
||||
* @experimental
|
||||
* NOTE: This is a private type and should not be exported
|
||||
*/
|
||||
export interface InjectorTypeWithProviders<T> {
|
||||
ngModule: InjectorType<T>;
|
||||
@ -120,12 +128,10 @@ export interface InjectorTypeWithProviders<T> {
|
||||
export function defineInjectable<T>(opts: {
|
||||
providedIn?: Type<any>| 'root' | 'any' | null,
|
||||
factory: () => T,
|
||||
}): InjectableDef<T> {
|
||||
return {
|
||||
providedIn: opts.providedIn as any || null,
|
||||
factory: opts.factory,
|
||||
value: undefined,
|
||||
};
|
||||
}): never {
|
||||
return ({
|
||||
providedIn: opts.providedIn as any || null, factory: opts.factory, value: undefined,
|
||||
} as InjectableDef<T>) as never;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -149,10 +155,8 @@ export function defineInjectable<T>(opts: {
|
||||
* @experimental
|
||||
*/
|
||||
export function defineInjector(options: {factory: () => any, providers?: any[], imports?: any[]}):
|
||||
InjectorDef<any> {
|
||||
return {
|
||||
factory: options.factory,
|
||||
providers: options.providers || [],
|
||||
imports: options.imports || [],
|
||||
};
|
||||
never {
|
||||
return ({
|
||||
factory: options.factory, providers: options.providers || [], imports: options.imports || [],
|
||||
} as InjectorDef<any>) as never;
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ export class InjectionToken<T> {
|
||||
/** @internal */
|
||||
readonly ngMetadataName = 'InjectionToken';
|
||||
|
||||
readonly ngInjectableDef: InjectableDef<T>|undefined;
|
||||
readonly ngInjectableDef: never|undefined;
|
||||
|
||||
constructor(protected _desc: string, options?: {
|
||||
providedIn?: Type<any>| 'root' | null,
|
||||
@ -71,6 +71,4 @@ export class InjectionToken<T> {
|
||||
toString(): string { return `InjectionToken ${this._desc}`; }
|
||||
}
|
||||
|
||||
export interface InjectableDefToken<T> extends InjectionToken<T> {
|
||||
ngInjectableDef: InjectableDef<T>;
|
||||
}
|
||||
export interface InjectableDefToken<T> extends InjectionToken<T> { ngInjectableDef: never; }
|
||||
|
@ -326,7 +326,7 @@ export class R3Injector {
|
||||
}
|
||||
|
||||
function injectableDefRecord(token: Type<any>| InjectionToken<any>): Record<any> {
|
||||
const def = (token as InjectableType<any>).ngInjectableDef;
|
||||
const def = (token as InjectableType<any>).ngInjectableDef as InjectableDef<any>;
|
||||
if (def === undefined) {
|
||||
throw new Error(`Type ${stringify(token)} is missing an ngInjectableDef definition.`);
|
||||
}
|
||||
|
Reference in New Issue
Block a user