Skip to content

Commit

Permalink
fix(core): allow abstract class as injection token
Browse files Browse the repository at this point in the history
  • Loading branch information
trotyl committed Jul 31, 2018
1 parent 3f20a2f commit d88279c
Show file tree
Hide file tree
Showing 9 changed files with 28 additions and 23 deletions.
3 changes: 2 additions & 1 deletion packages/compiler/src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,8 @@ export const createSelf = makeMetadataFactory('Self');
export const createSkipSelf = makeMetadataFactory('SkipSelf');
export const createHost = makeMetadataFactory('Host');

export interface Type extends Function { new (...args: any[]): any; }
export interface Type extends Function { prototype: any; }

export const Type = Function;

export enum SecurityContext {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/application_ref.ts
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,7 @@ export class ApplicationRef {

// Create a factory associated with the current module if it's not bound to some other
const ngModule = componentFactory instanceof ComponentFactoryBoundToModule ?
null :
undefined :
this._injector.get(NgModuleRef);
const selectorOrNode = rootSelectorOrNode || componentFactory.selector;
const compRef = componentFactory.create(Injector.NULL, [], selectorOrNode, ngModule);
Expand Down
8 changes: 4 additions & 4 deletions packages/core/src/di/injectable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import {R3_COMPILE_INJECTABLE} from '../ivy_switch';
import {ReflectionCapabilities} from '../reflection/reflection_capabilities';
import {Type} from '../type';
import {Constructor, Type} from '../type';
import {makeDecorator, makeParamDecorator} from '../util/decorators';
import {getClosureSafeProperty} from '../util/property';

Expand Down Expand Up @@ -69,7 +69,7 @@ export function convertInjectableProviderToFactory(
const reflectionCapabilities = new ReflectionCapabilities();
const deps = reflectionCapabilities.parameters(type);
// TODO - convert to flags.
return () => new type(...injectArgs(deps as any[]));
return () => new (type as Constructor<any>)(...injectArgs(deps as any[]));
}

if (USE_VALUE in provider) {
Expand All @@ -88,14 +88,14 @@ export function convertInjectableProviderToFactory(
const reflectionCapabilities = new ReflectionCapabilities();
deps = reflectionCapabilities.parameters(type);
}
return () => new classProvider.useClass(...injectArgs(deps));
return () => new (classProvider.useClass as Constructor<any>)(...injectArgs(deps));
} else {
let deps = (provider as ConstructorSansProvider).deps;
if (!deps) {
const reflectionCapabilities = new ReflectionCapabilities();
deps = reflectionCapabilities.parameters(type);
}
return () => new type(...injectArgs(deps !));
return () => new (type as Constructor<any>)(...injectArgs(deps !));
}
}

Expand Down
6 changes: 3 additions & 3 deletions packages/core/src/di/r3_injector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/

import {OnDestroy} from '../metadata/lifecycle_hooks';
import {Type} from '../type';
import {Constructor, Type} from '../type';
import {stringify} from '../util';

import {InjectableDef, InjectableType, InjectorDef, InjectorType, InjectorTypeWithProviders} from './defs';
Expand Down Expand Up @@ -338,7 +338,7 @@ function injectableDefRecord(token: Type<any>| InjectionToken<any>): Record<any>
}
// TODO(alxhub): there should probably be a strict mode which throws here instead of assuming a
// no-args constructor.
return makeRecord(() => new (token as Type<any>)());
return makeRecord(() => new (token as Constructor<any>)());
}
return makeRecord(def.factory);
}
Expand All @@ -360,7 +360,7 @@ function providerToRecord(provider: SingleProvider): Record<any> {
} else {
const classRef = (provider as StaticClassProvider | ClassProvider).useClass || token;
if (hasDeps(provider)) {
factory = () => new (classRef)(...injectArgs(provider.deps));
factory = () => new (classRef as Constructor<any>)(...injectArgs(provider.deps));
} else {
return injectableDefRecord(classRef);
}
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/reflection/reflection_capabilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

import {Type, isType} from '../type';
import {Constructor, Type, isType} from '../type';
import {global, stringify} from '../util';
import {ANNOTATIONS, PARAMETERS, PROP_METADATA} from '../util/decorators';

Expand All @@ -29,7 +29,7 @@ export class ReflectionCapabilities implements PlatformReflectionCapabilities {

isReflectionEnabled(): boolean { return true; }

factory<T>(t: Type<T>): (args: any[]) => T { return (...args: any[]) => new t(...args); }
factory<T>(t: Constructor<T>): (args: any[]) => T { return (...args: any[]) => new t(...args); }

/** @internal */
_zipTypesAndAnnotations(paramTypes: any[], paramAnnotations: any[]): any[][] {
Expand Down
5 changes: 3 additions & 2 deletions packages/core/src/render3/component_ref.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {LifecycleHooksFeature, createRootContext} from './component';
import {baseDirectiveCreate, createLNode, createLViewData, createTView, elementCreate, enterView, hostElement, initChangeDetectorIfExisting, locateHostElement, renderEmbeddedTemplate} from './instructions';
import {ComponentDefInternal, ComponentType, RenderFlags} from './interfaces/definition';
import {LElementNode, TNode, TNodeType} from './interfaces/node';
import {RElement, domRendererFactory3} from './interfaces/renderer';
import {RElement, RendererFactory3, domRendererFactory3} from './interfaces/renderer';
import {CONTEXT, FLAGS, INJECTOR, LViewData, LViewFlags, RootContext, TVIEW} from './interfaces/view';
import {RootViewRef, ViewRef} from './view_ref';

Expand Down Expand Up @@ -84,8 +84,9 @@ export class ComponentFactory<T> extends viewEngine_ComponentFactory<T> {
ngModule?: viewEngine_NgModuleRef<any>|undefined): viewEngine_ComponentRef<T> {
const isInternalRootView = rootSelectorOrNode === undefined;

// Cannot call method of union type: https://github.com/Microsoft/TypeScript/issues/7294
const rendererFactory =
ngModule ? ngModule.injector.get(RendererFactory2) : domRendererFactory3;
ngModule ? ngModule.injector.get<RendererFactory3>(RendererFactory2) : domRendererFactory3;
const hostNode = isInternalRootView ?
elementCreate(
this.selector, rendererFactory.createRenderer(null, this.componentDef.rendererType)) :
Expand Down
16 changes: 8 additions & 8 deletions packages/core/src/render3/definition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -232,13 +232,13 @@ export function defineComponent<T>(componentDefinition: {
outputs: invertObject(componentDefinition.outputs),
rendererType: resolveRendererType2(componentDefinition.rendererType) || null,
exportAs: componentDefinition.exportAs || null,
onInit: type.prototype.ngOnInit || null,
doCheck: type.prototype.ngDoCheck || null,
afterContentInit: type.prototype.ngAfterContentInit || null,
afterContentChecked: type.prototype.ngAfterContentChecked || null,
afterViewInit: type.prototype.ngAfterViewInit || null,
afterViewChecked: type.prototype.ngAfterViewChecked || null,
onDestroy: type.prototype.ngOnDestroy || null,
onInit: (type.prototype as any).ngOnInit || null,
doCheck: (type.prototype as any).ngDoCheck || null,
afterContentInit: (type.prototype as any).ngAfterContentInit || null,
afterContentChecked: (type.prototype as any).ngAfterContentChecked || null,
afterViewInit: (type.prototype as any).ngAfterViewInit || null,
afterViewChecked: (type.prototype as any).ngAfterViewChecked || null,
onDestroy: (type.prototype as any).ngOnDestroy || null,
onPush: componentDefinition.changeDetection === ChangeDetectionStrategy.OnPush,
directiveDefs: directiveTypes ?
() => (typeof directiveTypes === 'function' ? directiveTypes() : directiveTypes)
Expand Down Expand Up @@ -505,6 +505,6 @@ export function definePipe<T>(pipeDef: {
name: pipeDef.name,
factory: pipeDef.factory,
pure: pipeDef.pure !== false,
onDestroy: pipeDef.type.prototype.ngOnDestroy || null
onDestroy: (pipeDef.type.prototype as any).ngOnDestroy || null
}) as never;
}
4 changes: 3 additions & 1 deletion packages/core/src/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,6 @@ export function isType(v: any): v is Type<any> {
return typeof v === 'function';
}

export interface Type<T> extends Function { new (...args: any[]): T; }
export interface Type<T> extends Function { prototype: T; }

export interface Constructor<T> extends Type<T> { new (...args: any[]): T; }
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ class ToDoAppComponent {

// NON-NORMATIVE
(ToDoAppComponent.ngComponentDef as r3.ComponentDefInternal<any>).directiveDefs = () =>
[ToDoItemComponent.ngComponentDef, (NgForOf as r3.DirectiveType<NgForOf<any>>).ngDirectiveDef];
[ToDoItemComponent.ngComponentDef,
(NgForOf as any as r3.DirectiveType<NgForOf<any>>).ngDirectiveDef];
// /NON-NORMATIVE

@Component({
Expand Down

0 comments on commit d88279c

Please sign in to comment.