feat(ivy): support generation of flags for directive injection (#23345)

This change changes:
- compiler uses `directiveInject` instead of `inject` for `Directive`s
- unifies the flags in `di` as well as `render3`
- changes the signature of `directiveInject` to match `inject` In prep for #23330
- compiler now generates flags for injection.

Compiler portion of #23342
Prep for #23330

PR Close #23345
This commit is contained in:
Misko Hevery 2018-04-12 12:30:21 -07:00 committed by Igor Minar
parent 490772e680
commit 6f213a74f2
13 changed files with 152 additions and 46 deletions

View File

@ -2257,7 +2257,7 @@ describe('ngc transformer command-line', () => {
constructor(e: Existing) {} constructor(e: Existing) {}
} }
`); `);
expect(source).toMatch(/ngInjectableDef.*return ..\(..\.inject\(Existing, undefined, 1\)/); expect(source).toMatch(/ngInjectableDef.*return ..\(..\.inject\(Existing, undefined, 4\)/);
}); });
it('compiles a service that depends on a token', () => { it('compiles a service that depends on a token', () => {

View File

@ -217,14 +217,23 @@ export const enum DepFlags {
Value = 1 << 3, Value = 1 << 3,
} }
/** Injection flags for DI. */ /**
* Injection flags for DI.
*/
export const enum InjectFlags { export const enum InjectFlags {
Default = 0, Default = 0,
/** Skip the node that is requesting injection. */ /**
SkipSelf = 1 << 0, * Specifies that an injector should retrieve a dependency from any injector until reaching the
* host element of the current component. (Only used with Element Injector)
*/
Host = 1 << 0,
/** Don't descend into ancestors of the node requesting injection. */ /** Don't descend into ancestors of the node requesting injection. */
Self = 1 << 1, Self = 1 << 1,
/** Skip the node that is requesting injection. */
SkipSelf = 1 << 2,
/** Inject `defaultValue` instead if token not found. */
Optional = 1 << 3,
} }
export const enum ArgumentType {Inline = 0, Dynamic = 1} export const enum ArgumentType {Inline = 0, Dynamic = 1}

View File

@ -81,6 +81,8 @@ export class Identifiers {
static directiveLifeCycle: o.ExternalReference = {name: 'ɵl', moduleName: CORE}; static directiveLifeCycle: o.ExternalReference = {name: 'ɵl', moduleName: CORE};
static injectAttribute: o.ExternalReference = {name: 'ɵinjectAttribute', moduleName: CORE};
static injectElementRef: o.ExternalReference = {name: 'ɵinjectElementRef', moduleName: CORE}; static injectElementRef: o.ExternalReference = {name: 'ɵinjectElementRef', moduleName: CORE};
static injectTemplateRef: o.ExternalReference = {name: 'ɵinjectTemplateRef', moduleName: CORE}; static injectTemplateRef: o.ExternalReference = {name: 'ɵinjectTemplateRef', moduleName: CORE};
@ -88,7 +90,7 @@ export class Identifiers {
static injectViewContainerRef: static injectViewContainerRef:
o.ExternalReference = {name: 'ɵinjectViewContainerRef', moduleName: CORE}; o.ExternalReference = {name: 'ɵinjectViewContainerRef', moduleName: CORE};
static inject: o.ExternalReference = {name: inject', moduleName: CORE}; static directiveInject: o.ExternalReference = {name: directiveInject', moduleName: CORE};
static defineComponent: o.ExternalReference = {name: 'ɵdefineComponent', moduleName: CORE}; static defineComponent: o.ExternalReference = {name: 'ɵdefineComponent', moduleName: CORE};

View File

@ -6,10 +6,11 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {CompileDirectiveMetadata, CompileDirectiveSummary, CompilePipeSummary, CompileQueryMetadata, CompileTokenMetadata, CompileTypeMetadata, CompileTypeSummary, flatten, identifierName, rendererTypeName, sanitizeIdentifier, tokenReference, viewClassName} from '../compile_metadata'; import {CompileDiDependencyMetadata, CompileDirectiveMetadata, CompileDirectiveSummary, CompilePipeSummary, CompileQueryMetadata, CompileTokenMetadata, CompileTypeMetadata, CompileTypeSummary, flatten, identifierName, rendererTypeName, sanitizeIdentifier, tokenReference, viewClassName} from '../compile_metadata';
import {CompileReflector} from '../compile_reflector'; import {CompileReflector} from '../compile_reflector';
import {BindingForm, BuiltinConverter, BuiltinFunctionCall, ConvertPropertyBindingResult, EventHandlerVars, LocalResolver, convertActionBinding, convertPropertyBinding, convertPropertyBindingBuiltins} from '../compiler_util/expression_converter'; import {BindingForm, BuiltinConverter, BuiltinFunctionCall, ConvertPropertyBindingResult, EventHandlerVars, LocalResolver, convertActionBinding, convertPropertyBinding, convertPropertyBindingBuiltins} from '../compiler_util/expression_converter';
import {ConstantPool, DefinitionKind} from '../constant_pool'; import {ConstantPool, DefinitionKind} from '../constant_pool';
import {InjectFlags} from '../core';
import {AST, AstMemoryEfficientTransformer, AstTransformer, BindingPipe, FunctionCall, ImplicitReceiver, LiteralArray, LiteralMap, LiteralPrimitive, MethodCall, ParseSpan, PropertyRead} from '../expression_parser/ast'; import {AST, AstMemoryEfficientTransformer, AstTransformer, BindingPipe, FunctionCall, ImplicitReceiver, LiteralArray, LiteralMap, LiteralPrimitive, MethodCall, ParseSpan, PropertyRead} from '../expression_parser/ast';
import {Identifiers} from '../identifiers'; import {Identifiers} from '../identifiers';
import {LifecycleHooks} from '../lifecycle_reflector'; import {LifecycleHooks} from '../lifecycle_reflector';
@ -19,9 +20,11 @@ import {CssSelector} from '../selector';
import {BindingParser} from '../template_parser/binding_parser'; import {BindingParser} from '../template_parser/binding_parser';
import {AttrAst, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, DirectiveAst, ElementAst, EmbeddedTemplateAst, NgContentAst, PropertyBindingType, ProviderAst, QueryMatch, RecursiveTemplateAstVisitor, ReferenceAst, TemplateAst, TemplateAstVisitor, TextAst, VariableAst, templateVisitAll} from '../template_parser/template_ast'; import {AttrAst, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, DirectiveAst, ElementAst, EmbeddedTemplateAst, NgContentAst, PropertyBindingType, ProviderAst, QueryMatch, RecursiveTemplateAstVisitor, ReferenceAst, TemplateAst, TemplateAstVisitor, TextAst, VariableAst, templateVisitAll} from '../template_parser/template_ast';
import {OutputContext, error} from '../util'; import {OutputContext, error} from '../util';
import {Identifiers as R3} from './r3_identifiers'; import {Identifiers as R3} from './r3_identifiers';
import {BUILD_OPTIMIZER_COLOCATE, OutputMode} from './r3_types'; import {BUILD_OPTIMIZER_COLOCATE, OutputMode} from './r3_types';
/** Name of the context parameter passed into a template function */ /** Name of the context parameter passed into a template function */
const CONTEXT_NAME = 'ctx'; const CONTEXT_NAME = 'ctx';
@ -927,12 +930,6 @@ export function createFactory(
const viewContainerRef = reflector.resolveExternalReference(Identifiers.ViewContainerRef); const viewContainerRef = reflector.resolveExternalReference(Identifiers.ViewContainerRef);
for (let dependency of type.diDeps) { for (let dependency of type.diDeps) {
if (dependency.isValue) {
unsupported('value dependencies');
}
if (dependency.isHost) {
unsupported('host dependencies');
}
const token = dependency.token; const token = dependency.token;
if (token) { if (token) {
const tokenRef = tokenReference(token); const tokenRef = tokenReference(token);
@ -942,10 +939,18 @@ export function createFactory(
args.push(o.importExpr(R3.injectTemplateRef).callFn([])); args.push(o.importExpr(R3.injectTemplateRef).callFn([]));
} else if (tokenRef === viewContainerRef) { } else if (tokenRef === viewContainerRef) {
args.push(o.importExpr(R3.injectViewContainerRef).callFn([])); args.push(o.importExpr(R3.injectViewContainerRef).callFn([]));
} else if (dependency.isAttribute) {
args.push(o.importExpr(R3.injectAttribute).callFn([o.literal(dependency.token !.value)]));
} else { } else {
const value = const tokenValue =
token.identifier != null ? outputCtx.importExpr(tokenRef) : o.literal(tokenRef); token.identifier != null ? outputCtx.importExpr(tokenRef) : o.literal(tokenRef);
args.push(o.importExpr(R3.inject).callFn([value])); const directiveInjectArgs = [tokenValue];
const flags = extractFlags(dependency);
if (flags != InjectFlags.Default) {
// Append flag information if other than default.
directiveInjectArgs.push(o.literal(undefined), o.literal(flags));
}
args.push(o.importExpr(R3.directiveInject).callFn(directiveInjectArgs));
} }
} else { } else {
unsupported('dependency without a token'); unsupported('dependency without a token');
@ -979,6 +984,26 @@ export function createFactory(
type.reference.name ? `${type.reference.name}_Factory` : null); type.reference.name ? `${type.reference.name}_Factory` : null);
} }
function extractFlags(dependency: CompileDiDependencyMetadata): InjectFlags {
let flags = InjectFlags.Default;
if (dependency.isHost) {
flags |= InjectFlags.Host;
}
if (dependency.isOptional) {
flags |= InjectFlags.Optional;
}
if (dependency.isSelf) {
flags |= InjectFlags.Self;
}
if (dependency.isSkipSelf) {
flags |= InjectFlags.SkipSelf;
}
if (dependency.isValue) {
unsupported('value dependencies');
}
return flags;
}
/** /**
* Remove trailing null nodes as they are implied. * Remove trailing null nodes as they are implied.
*/ */

View File

@ -0,0 +1,70 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {MockDirectory, setup} from '../aot/test_util';
import {compile, expectEmit} from './mock_compile';
describe('compiler compliance: dependency injection', () => {
const angularFiles = setup({
compileAngular: true,
compileAnimations: false,
compileCommon: true,
});
it('should create factory methods', () => {
const files = {
app: {
'spec.ts': `
import {Component, NgModule, Injectable, Attribute, Host, SkipSelf, Self, Optional} from '@angular/core';
import {CommonModule} from '@angular/common';
@Injectable()
export class MyService {}
@Component({
selector: 'my-component',
template: \`\`
})
export class MyComponent {
constructor(
@Attribute('name') name:string,
s1: MyService,
@Host() s2: MyService,
@Self() s4: MyService,
@SkipSelf() s3: MyService,
@Optional() s5: MyService,
@Self() @Optional() s6: MyService,
) {}
}
@NgModule({declarations: [MyComponent], imports: [CommonModule], providers: [MyService]})
export class MyModule {}
`
}
};
const factory = `
factory: function MyComponent_Factory() {
return new MyComponent(
$r3$.ɵinjectAttribute('name'),
$r3$.ɵdirectiveInject(MyService),
$r3$.ɵdirectiveInject(MyService, (undefined as any), 1),
$r3$.ɵdirectiveInject(MyService, (undefined as any), 2),
$r3$.ɵdirectiveInject(MyService, (undefined as any), 4),
$r3$.ɵdirectiveInject(MyService, (undefined as any), 8),
$r3$.ɵdirectiveInject(MyService, (undefined as any), 10)
);
}`;
const result = compile(files, angularFiles);
expectEmit(result.source, factory, 'Incorrect factory');
});
});

View File

@ -21,7 +21,6 @@ export {
injectViewContainerRef as ɵinjectViewContainerRef, injectViewContainerRef as ɵinjectViewContainerRef,
injectChangeDetectorRef as ɵinjectChangeDetectorRef, injectChangeDetectorRef as ɵinjectChangeDetectorRef,
injectAttribute as ɵinjectAttribute, injectAttribute as ɵinjectAttribute,
InjectFlags as ɵInjectFlags,
PublicFeature as ɵPublicFeature, PublicFeature as ɵPublicFeature,
NgOnChangesFeature as ɵNgOnChangesFeature, NgOnChangesFeature as ɵNgOnChangesFeature,
CssSelectorList as ɵCssSelectorList, CssSelectorList as ɵCssSelectorList,

View File

@ -411,16 +411,21 @@ function getClosureSafeProperty<T>(objWithPropertyToExtract: T): string {
/** /**
* Injection flags for DI. * Injection flags for DI.
*
*
*/ */
export const enum InjectFlags { export const enum InjectFlags {
Default = 0, Default = 0,
/** Skip the node that is requesting injection. */ /**
SkipSelf = 1 << 0, * Specifies that an injector should retrieve a dependency from any injector until reaching the
* host element of the current component. (Only used with Element Injector)
*/
Host = 1 << 0,
/** Don't descend into ancestors of the node requesting injection. */ /** Don't descend into ancestors of the node requesting injection. */
Self = 1 << 1, Self = 1 << 1,
/** Skip the node that is requesting injection. */
SkipSelf = 1 << 2,
/** Inject `defaultValue` instead if token not found. */
Optional = 1 << 3,
} }
let _currentInjector: Injector|null = null; let _currentInjector: Injector|null = null;

View File

@ -9,7 +9,7 @@
// We are temporarily importing the existing viewEngine_from core so we can be sure we are // We are temporarily importing the existing viewEngine_from core so we can be sure we are
// correctly implementing its interfaces for backwards compatibility. // correctly implementing its interfaces for backwards compatibility.
import {ChangeDetectorRef as viewEngine_ChangeDetectorRef} from '../change_detection/change_detector_ref'; import {ChangeDetectorRef as viewEngine_ChangeDetectorRef} from '../change_detection/change_detector_ref';
import {Injector} from '../di/injector'; import {InjectFlags, Injector} from '../di/injector';
import {ComponentFactory as viewEngine_ComponentFactory, ComponentRef as viewEngine_ComponentRef} from '../linker/component_factory'; import {ComponentFactory as viewEngine_ComponentFactory, ComponentRef as viewEngine_ComponentRef} from '../linker/component_factory';
import {ElementRef as viewEngine_ElementRef} from '../linker/element_ref'; import {ElementRef as viewEngine_ElementRef} from '../linker/element_ref';
import {NgModuleRef as viewEngine_NgModuleRef} from '../linker/ng_module_factory'; import {NgModuleRef as viewEngine_NgModuleRef} from '../linker/ng_module_factory';
@ -133,19 +133,6 @@ export function getOrCreateNodeInjectorForNode(node: LElementNode | LContainerNo
}; };
} }
/** Injection flags for DI. */
export const enum InjectFlags {
/** Dependency is not required. Null will be injected if there is no provider for the dependency.
*/
Optional = 1 << 0,
/** When resolving a dependency, include the node that is requesting injection. */
CheckSelf = 1 << 1,
/** When resolving a dependency, include ancestors of the node requesting injection. */
CheckParent = 1 << 2,
/** Default injection options: required, checks both self and ancestors. */
Default = CheckSelf | CheckParent,
}
/** /**
* Constructs an injection error with the given text and token. * Constructs an injection error with the given text and token.
* *
@ -201,8 +188,14 @@ export function diPublic(def: DirectiveDef<any>): void {
* @param flags Injection flags (e.g. CheckParent) * @param flags Injection flags (e.g. CheckParent)
* @returns The instance found * @returns The instance found
*/ */
export function directiveInject<T>(token: Type<T>, flags?: InjectFlags, defaultValue?: T): T { export function directiveInject<T>(
return getOrCreateInjectable<T>(getOrCreateNodeInjector(), token, flags, defaultValue); token: Type<T>, notFoundValue?: undefined, flags?: InjectFlags): T;
export function directiveInject<T>(token: Type<T>, notFoundValue: T, flags?: InjectFlags): T;
export function directiveInject<T>(token: Type<T>, notFoundValue: null, flags?: InjectFlags): T|
null;
export function directiveInject<T>(
token: Type<T>, notFoundValue?: T | null, flags = InjectFlags.Default): T|null {
return getOrCreateInjectable<T>(getOrCreateNodeInjector(), token, flags, notFoundValue);
} }
/** /**
@ -352,7 +345,7 @@ function getClosestComponentAncestor(node: LViewNode | LElementNode): LElementNo
* @returns The instance found * @returns The instance found
*/ */
export function getOrCreateInjectable<T>( export function getOrCreateInjectable<T>(
di: LInjector, token: Type<T>, flags?: InjectFlags, defaultValue?: T): T { di: LInjector, token: Type<T>, flags?: InjectFlags, defaultValue?: T | null): T|null {
const bloomHash = bloomHashBit(token); const bloomHash = bloomHashBit(token);
// If the token has a bloom hash, then it is a directive that is public to the injection system // If the token has a bloom hash, then it is a directive that is public to the injection system

View File

@ -8,10 +8,9 @@
import {LifecycleHooksFeature, createComponentRef, getHostElement, getRenderedText, renderComponent, whenRendered} from './component'; import {LifecycleHooksFeature, createComponentRef, getHostElement, getRenderedText, renderComponent, whenRendered} from './component';
import {NgOnChangesFeature, PublicFeature, defineComponent, defineDirective, definePipe} from './definition'; import {NgOnChangesFeature, PublicFeature, defineComponent, defineDirective, definePipe} from './definition';
import {InjectFlags} from './di';
import {ComponentDef, ComponentTemplate, ComponentType, DirectiveDef, DirectiveDefFlags, DirectiveType, PipeDef} from './interfaces/definition'; import {ComponentDef, ComponentTemplate, ComponentType, DirectiveDef, DirectiveDefFlags, DirectiveType, PipeDef} from './interfaces/definition';
export {InjectFlags, QUERY_READ_CONTAINER_REF, QUERY_READ_ELEMENT_REF, QUERY_READ_FROM_NODE, QUERY_READ_TEMPLATE_REF, directiveInject, injectAttribute, injectChangeDetectorRef, injectElementRef, injectTemplateRef, injectViewContainerRef} from './di'; export {QUERY_READ_CONTAINER_REF, QUERY_READ_ELEMENT_REF, QUERY_READ_FROM_NODE, QUERY_READ_TEMPLATE_REF, directiveInject, injectAttribute, injectChangeDetectorRef, injectElementRef, injectTemplateRef, injectViewContainerRef} from './di';
export {RenderFlags} from './interfaces/definition'; export {RenderFlags} from './interfaces/definition';
export {CssSelectorList} from './interfaces/projection'; export {CssSelectorList} from './interfaces/projection';

View File

@ -7,10 +7,10 @@
*/ */
import {NgForOf as NgForOfDef, NgIf as NgIfDef} from '@angular/common'; import {NgForOf as NgForOfDef, NgIf as NgIfDef} from '@angular/common';
import {IterableDiffers} from '@angular/core'; import {InjectFlags, IterableDiffers} from '@angular/core';
import {defaultIterableDiffers} from '../../src/change_detection/change_detection'; import {defaultIterableDiffers} from '../../src/change_detection/change_detection';
import {DirectiveType, InjectFlags, NgOnChangesFeature, defineDirective, directiveInject, injectTemplateRef, injectViewContainerRef} from '../../src/render3/index'; import {DirectiveType, NgOnChangesFeature, defineDirective, directiveInject, injectTemplateRef, injectViewContainerRef} from '../../src/render3/index';
export const NgForOf: DirectiveType<NgForOfDef<any>> = NgForOfDef as any; export const NgForOf: DirectiveType<NgForOfDef<any>> = NgForOfDef as any;
export const NgIf: DirectiveType<NgIfDef> = NgIfDef as any; export const NgIf: DirectiveType<NgIfDef> = NgIfDef as any;
@ -20,7 +20,7 @@ NgForOf.ngDirectiveDef = defineDirective({
selectors: [['', 'ngForOf', '']], selectors: [['', 'ngForOf', '']],
factory: () => new NgForOfDef( factory: () => new NgForOfDef(
injectViewContainerRef(), injectTemplateRef(), injectViewContainerRef(), injectTemplateRef(),
directiveInject(IterableDiffers, InjectFlags.Default, defaultIterableDiffers)), directiveInject(IterableDiffers, defaultIterableDiffers, InjectFlags.Default)),
features: [NgOnChangesFeature()], features: [NgOnChangesFeature()],
inputs: { inputs: {
ngForOf: 'ngForOf', ngForOf: 'ngForOf',

View File

@ -6,10 +6,12 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import * as $core$ from '../../../index';
import {ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, ContentChildren, Directive, HostBinding, HostListener, Injectable, Input, NgModule, OnDestroy, Optional, Pipe, PipeTransform, QueryList, SimpleChanges, TemplateRef, ViewChild, ViewChildren, ViewContainerRef} from '../../../src/core'; import {ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, ContentChildren, Directive, HostBinding, HostListener, Injectable, Input, NgModule, OnDestroy, Optional, Pipe, PipeTransform, QueryList, SimpleChanges, TemplateRef, ViewChild, ViewChildren, ViewContainerRef} from '../../../src/core';
import * as $r3$ from '../../../src/core_render3_private_export'; import * as $r3$ from '../../../src/core_render3_private_export';
import {renderComponent, toHtml} from '../render_util'; import {renderComponent, toHtml} from '../render_util';
/// See: `normative.md` /// See: `normative.md`
xdescribe('NgModule', () => { xdescribe('NgModule', () => {
@ -69,7 +71,7 @@ xdescribe('NgModule', () => {
static ngInjectableDef = defineInjectable({ static ngInjectableDef = defineInjectable({
providedIn: MyModule, providedIn: MyModule,
factory: () => new BurntToast( factory: () => new BurntToast(
$r3$.ɵdirectiveInject(Toast, $r3$.ɵInjectFlags.Optional), $r3$.ɵdirectiveInject(Toast, undefined, $core$.InjectFlags.Optional),
$r3$.ɵdirectiveInject(String)), $r3$.ɵdirectiveInject(String)),
}); });
// /NORMATIVE // /NORMATIVE

View File

@ -6,11 +6,11 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {ChangeDetectorRef, ElementRef, TemplateRef, ViewContainerRef} from '@angular/core'; import {ChangeDetectorRef, ElementRef, InjectFlags, TemplateRef, ViewContainerRef} from '@angular/core';
import {RenderFlags} from '@angular/core/src/render3/interfaces/definition'; import {RenderFlags} from '@angular/core/src/render3/interfaces/definition';
import {defineComponent} from '../../src/render3/definition'; import {defineComponent} from '../../src/render3/definition';
import {InjectFlags, bloomAdd, bloomFindPossibleInjector, getOrCreateNodeInjector, injectAttribute} from '../../src/render3/di'; import {bloomAdd, bloomFindPossibleInjector, getOrCreateNodeInjector, injectAttribute} from '../../src/render3/di';
import {NgOnChangesFeature, PublicFeature, defineDirective, directiveInject, injectChangeDetectorRef, injectElementRef, injectTemplateRef, injectViewContainerRef} from '../../src/render3/index'; import {NgOnChangesFeature, PublicFeature, defineDirective, directiveInject, injectChangeDetectorRef, injectElementRef, injectTemplateRef, injectViewContainerRef} from '../../src/render3/index';
import {bind, container, containerRefreshEnd, containerRefreshStart, createLNode, createLView, createTView, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, enterView, interpolation2, leaveView, load, projection, projectionDef, text, textBinding} from '../../src/render3/instructions'; import {bind, container, containerRefreshEnd, containerRefreshStart, createLNode, createLView, createTView, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, enterView, interpolation2, leaveView, load, projection, projectionDef, text, textBinding} from '../../src/render3/instructions';
import {LInjector} from '../../src/render3/interfaces/injector'; import {LInjector} from '../../src/render3/interfaces/injector';
@ -1019,7 +1019,7 @@ describe('di', () => {
type: MyApp, type: MyApp,
selectors: [['my-app']], selectors: [['my-app']],
factory: () => new MyApp( factory: () => new MyApp(
directiveInject(String as any, InjectFlags.Default, 'DefaultValue')), directiveInject(String as any, 'DefaultValue', InjectFlags.Default)),
template: () => null template: () => null
}); });
} }

View File

@ -376,8 +376,10 @@ export interface InjectDecorator {
export declare const enum InjectFlags { export declare const enum InjectFlags {
Default = 0, Default = 0,
SkipSelf = 1, Host = 1,
Self = 2, Self = 2,
SkipSelf = 4,
Optional = 8,
} }
export declare class InjectionToken<T> { export declare class InjectionToken<T> {