refactor(ivy): make return value of define(Component|Directive|Pipe|Injector|Injectable) private (#23371)

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 `OpaqueToken`.

By prefixing the type with `ɵ` we are communicating the the outside world that
the value is not public API and is subject to change without backward compatibility.

PR Close #23371
This commit is contained in:
Miško Hevery
2018-04-13 13:34:39 -07:00
committed by Igor Minar
parent f4017ce5e3
commit 2c09b707ce
32 changed files with 179 additions and 172 deletions

View File

@ -17,14 +17,15 @@ import {ClassProvider, ClassSansProvider, ConstructorProvider, ConstructorSansPr
* requesting injection of other types if necessary.
*
* Optionally, a `providedIn` parameter specifies that the given type belongs to a particular
* `InjectorDef`, `NgModule`, or a special scope (e.g. `'root'`). A value of `null` indicates
* `ɵ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.
* NOTE: This is a semi public API, and there are no guaranties that the shape of this API will
* remain consistent between version. Use with caution.
*
* @experimental
*/
export interface InjectableDef<T> {
export interface ɵInjectableDef<T> {
/**
* Specifies that the given type belongs to a particular injector:
* - `InjectorType` such as `NgModule`,
@ -50,13 +51,13 @@ export interface InjectableDef<T> {
* Information about the providers to be included in an `Injector` as well as how the given type
* which carries the information should be created by the DI system.
*
* An `InjectorDef` can import other types which have `InjectorDefs`, forming a deep nested
* An `ɵInjectorDef` can import other types which have `InjectorDefs`, forming a deep nested
* structure of providers with a defined priority (identically to how `NgModule`s also have
* an import/dependency structure).
*
* @experimental
*/
export interface InjectorDef<T> {
export interface ɵInjectorDef<T> {
factory: () => T;
// TODO(alxhub): Narrow down the type here once decorators properly change the return type of the
@ -68,29 +69,29 @@ export interface InjectorDef<T> {
}
/**
* A `Type` which has an `InjectableDef` static field.
* A `Type` which has an `ɵInjectableDef` static field.
*
* `InjectableDefType`s contain their own Dependency Injection metadata and are usable in an
* `InjectorDef`-based `StaticInjector.
* `ɵInjectorDef`-based `StaticInjector.
*
* @experimental
*/
export interface InjectableType<T> extends Type<T> { ngInjectableDef: InjectableDef<T>; }
export interface InjectableType<T> extends Type<T> { ngInjectableDef: ɵInjectableDef<T>; }
/**
* A type which has an `InjectorDef` static field.
* A type which has an `ɵInjectorDef` static field.
*
* `InjectorDefTypes` can be used to configure a `StaticInjector`.
*
* @experimental
*/
export interface InjectorType<T> extends Type<T> { ngInjectorDef: InjectorDef<T>; }
export interface InjectorType<T> extends Type<T> { ngInjectorDef: ɵInjectorDef<T>; }
/**
* Describes the `InjectorDef` equivalent of a `ModuleWithProviders`, an `InjectorDefType` with an
* Describes the `ɵInjectorDef` equivalent of a `ModuleWithProviders`, an `InjectorDefType` with an
* associated array of providers.
*
* Objects of this type can be listed in the imports section of an `InjectorDef`.
* Objects of this type can be listed in the imports section of an `ɵInjectorDef`.
*
* @experimental
*/
@ -102,7 +103,7 @@ export interface InjectorTypeWithProviders<T> {
/**
* Construct an `InjectableDef` which defines how a token will be constructed by the DI system, and
* Construct an `ɵInjectableDef` which defines how a token will be constructed by the DI system, and
* in which injectors (if any) it will be available.
*
* This should be assigned to a static `ngInjectableDef` field on a type, which will then be an
@ -120,7 +121,7 @@ export interface InjectorTypeWithProviders<T> {
export function defineInjectable<T>(opts: {
providedIn?: Type<any>| 'root' | 'any' | null,
factory: () => T,
}): InjectableDef<T> {
}): ɵInjectableDef<T> {
return {
providedIn: opts.providedIn as any || null,
factory: opts.factory,
@ -129,7 +130,7 @@ export function defineInjectable<T>(opts: {
}
/**
* Construct an `InjectorDef` which configures an injector.
* Construct an `ɵInjectorDef` which configures an injector.
*
* This should be assigned to a static `ngInjectorDef` field on a type, which will then be an
* `InjectorType`.
@ -149,7 +150,7 @@ export function defineInjectable<T>(opts: {
* @experimental
*/
export function defineInjector(options: {factory: () => any, providers?: any[], imports?: any[]}):
InjectorDef<any> {
ɵInjectorDef<any> {
return {
factory: options.factory,
providers: options.providers || [],

View File

@ -11,7 +11,7 @@ import {Type} from '../type';
import {makeDecorator, makeParamDecorator} from '../util/decorators';
import {getClosureSafeProperty} from '../util/property';
import {InjectableDef, InjectableType, defineInjectable} from './defs';
import {InjectableType, defineInjectable, ɵInjectableDef} from './defs';
import {inject, injectArgs} from './injector';
import {ClassSansProvider, ConstructorProvider, ConstructorSansProvider, ExistingProvider, ExistingSansProvider, FactoryProvider, FactorySansProvider, StaticClassProvider, StaticClassSansProvider, ValueProvider, ValueSansProvider} from './provider';
@ -134,4 +134,4 @@ export const Injectable: InjectableDecorator = makeDecorator(
*
* @experimental
*/
export interface InjectableType<T> extends Type<T> { ngInjectableDef: InjectableDef<T>; }
export interface InjectableType<T> extends Type<T> { ngInjectableDef: ɵInjectableDef<T>; }

View File

@ -8,7 +8,8 @@
import {Type} from '../type';
import {InjectableDef, defineInjectable} from './defs';
import {defineInjectable, ɵInjectableDef} from './defs';
/**
* Creates a token that can be used in a DI Provider.
@ -52,7 +53,7 @@ export class InjectionToken<T> {
/** @internal */
readonly ngMetadataName = 'InjectionToken';
readonly ngInjectableDef: InjectableDef<T>|undefined;
readonly ngInjectableDef: ɵInjectableDef<T>|undefined;
constructor(protected _desc: string, options?: {
providedIn?: Type<any>| 'root' | null,
@ -72,5 +73,5 @@ export class InjectionToken<T> {
}
export interface InjectableDefToken<T> extends InjectionToken<T> {
ngInjectableDef: InjectableDef<T>;
ngInjectableDef: ɵInjectableDef<T>;
}

View File

@ -9,7 +9,7 @@
import {Type} from '../type';
import {stringify} from '../util';
import {InjectableDef, defineInjectable} from './defs';
import {defineInjectable, ɵInjectableDef} from './defs';
import {resolveForwardRef} from './forward_ref';
import {InjectionToken} from './injection_token';
import {Inject, Optional, Self, SkipSelf} from './metadata';
@ -462,7 +462,7 @@ export function inject<T>(token: Type<T>| InjectionToken<T>, flags = InjectFlags
if (_currentInjector === undefined) {
throw new Error(`inject() must be called from an injection context`);
} else if (_currentInjector === null) {
const injectableDef: InjectableDef<T> = (token as any).ngInjectableDef;
const injectableDef: ɵInjectableDef<T> = (token as any).ngInjectableDef;
if (injectableDef && injectableDef.providedIn == 'root') {
return injectableDef.value === undefined ? injectableDef.value = injectableDef.factory() :
injectableDef.value;

View File

@ -10,7 +10,7 @@ import {OnDestroy} from '../metadata/lifecycle_hooks';
import {Type} from '../type';
import {stringify} from '../util';
import {InjectableDef, InjectableType, InjectorDef, InjectorType, InjectorTypeWithProviders} from './defs';
import {InjectableType, InjectorType, InjectorTypeWithProviders, ɵInjectableDef, ɵInjectorDef} from './defs';
import {resolveForwardRef} from './forward_ref';
import {InjectableDefToken, InjectionToken} from './injection_token';
import {INJECTOR, InjectFlags, Injector, NullInjector, THROW_IF_NOT_FOUND, USE_VALUE, inject, injectArgs, setCurrentInjector} from './injector';
@ -200,7 +200,7 @@ export class R3Injector {
// read, so care is taken to only do the read once.
// First attempt to read the ngInjectorDef.
let def = (defOrWrappedDef as InjectorType<any>).ngInjectorDef as(InjectorDef<any>| undefined);
let def = (defOrWrappedDef as InjectorType<any>).ngInjectorDef as(ɵInjectorDef<any>| undefined);
// If that's not present, then attempt to read ngModule from the InjectorDefTypeWithProviders.
const ngModule =
@ -219,7 +219,7 @@ export class R3Injector {
EMPTY_ARRAY;
// Finally, if defOrWrappedType was an `InjectorDefTypeWithProviders`, then the actual
// `InjectorDef` is on its `ngModule`.
// `ɵInjectorDef` is on its `ngModule`.
if (ngModule !== undefined) {
def = ngModule.ngInjectorDef;
}
@ -314,7 +314,7 @@ export class R3Injector {
return record.value as T;
}
private injectableDefInScope(def: InjectableDef<any>): boolean {
private injectableDefInScope(def: ɵInjectableDef<any>): boolean {
if (!def.providedIn) {
return false;
} else if (typeof def.providedIn === 'string') {