Skip to content

Commit 8da2c34

Browse files
trotylmhevery
authored andcommitted
fix(core): allow abstract class as injection token
closes angular#23611
1 parent d216a46 commit 8da2c34

File tree

9 files changed

+29
-20
lines changed

9 files changed

+29
-20
lines changed

packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/dep.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,4 @@ export class DepAppModule {
3838
@Injectable({providedIn: DepAppModule})
3939
export class ShakeableService {
4040
constructor(readonly normal: NormalService) {}
41-
}
41+
}

packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/token.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export class TokenModule {
1818

1919
export const TOKEN = new InjectionToken('test', {
2020
providedIn: TokenModule,
21-
factory: () => new Service(inject(Dep)),
21+
factory: () => new Service(inject(Dep), inject(AbstractDep)),
2222
});
2323

2424

@@ -49,6 +49,11 @@ export class Dep {
4949
readonly data = 'fromToken';
5050
}
5151

52+
@Injectable({providedIn: 'root', useValue: {value: 42}})
53+
export abstract class AbstractDep {
54+
abstract value: number;
55+
}
56+
5257
export class Service {
53-
constructor(readonly dep: Dep) {}
58+
constructor(readonly dep: Dep, unused: AbstractDep) {}
5459
}

packages/compiler/src/core.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,8 @@ export const createSelf = makeMetadataFactory('Self');
154154
export const createSkipSelf = makeMetadataFactory('SkipSelf');
155155
export const createHost = makeMetadataFactory('Host');
156156

157-
export interface Type extends Function { new (...args: any[]): any; }
157+
export interface Type extends Function { prototype: any; }
158+
158159
export const Type = Function;
159160

160161
export enum SecurityContext {

packages/core/src/application_ref.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -465,7 +465,7 @@ export class ApplicationRef {
465465

466466
// Create a factory associated with the current module if it's not bound to some other
467467
const ngModule = componentFactory instanceof ComponentFactoryBoundToModule ?
468-
null :
468+
undefined :
469469
this._injector.get(NgModuleRef);
470470
const selectorOrNode = rootSelectorOrNode || componentFactory.selector;
471471
const compRef = componentFactory.create(Injector.NULL, [], selectorOrNode, ngModule);

packages/core/src/di/r3_injector.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*/
88

99
import {OnDestroy} from '../metadata/lifecycle_hooks';
10-
import {Type} from '../type';
10+
import {Constructor, Type} from '../type';
1111
import {stringify} from '../util';
1212

1313
import {InjectableDef, InjectableType, InjectorType, InjectorTypeWithProviders, getInjectableDef, getInjectorDef} from './defs';
@@ -336,7 +336,7 @@ function injectableDefRecord(token: Type<any>| InjectionToken<any>): Record<any>
336336
}
337337
// TODO(alxhub): there should probably be a strict mode which throws here instead of assuming a
338338
// no-args constructor.
339-
return makeRecord(() => new (token as Type<any>)());
339+
return makeRecord(() => new (token as Constructor<any>)());
340340
}
341341
return makeRecord(injectableDef.factory);
342342
}
@@ -358,7 +358,7 @@ function providerToRecord(provider: SingleProvider): Record<any> {
358358
} else {
359359
const classRef = (provider as StaticClassProvider | ClassProvider).useClass || token;
360360
if (hasDeps(provider)) {
361-
factory = () => new (classRef)(...injectArgs(provider.deps));
361+
factory = () => new (classRef as Constructor<any>)(...injectArgs(provider.deps));
362362
} else {
363363
return injectableDefRecord(classRef);
364364
}

packages/core/src/reflection/reflection_capabilities.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {Type, isType} from '../type';
9+
import {Constructor, Type, isType} from '../type';
1010
import {global, stringify} from '../util';
1111
import {ANNOTATIONS, PARAMETERS, PROP_METADATA} from '../util/decorators';
1212

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

3030
isReflectionEnabled(): boolean { return true; }
3131

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

3434
/** @internal */
3535
_zipTypesAndAnnotations(paramTypes: any[], paramAnnotations: any[]): any[][] {

packages/core/src/render3/definition.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -296,13 +296,13 @@ export function defineComponent<T>(componentDefinition: {
296296
declaredInputs: declaredInputs,
297297
outputs: invertObject(componentDefinition.outputs),
298298
exportAs: componentDefinition.exportAs || null,
299-
onInit: type.prototype.ngOnInit || null,
300-
doCheck: type.prototype.ngDoCheck || null,
301-
afterContentInit: type.prototype.ngAfterContentInit || null,
302-
afterContentChecked: type.prototype.ngAfterContentChecked || null,
303-
afterViewInit: type.prototype.ngAfterViewInit || null,
304-
afterViewChecked: type.prototype.ngAfterViewChecked || null,
305-
onDestroy: type.prototype.ngOnDestroy || null,
299+
onInit: (type.prototype as any).ngOnInit || null,
300+
doCheck: (type.prototype as any).ngDoCheck || null,
301+
afterContentInit: (type.prototype as any).ngAfterContentInit || null,
302+
afterContentChecked: (type.prototype as any).ngAfterContentChecked || null,
303+
afterViewInit: (type.prototype as any).ngAfterViewInit || null,
304+
afterViewChecked: (type.prototype as any).ngAfterViewChecked || null,
305+
onDestroy: (type.prototype as any).ngOnDestroy || null,
306306
onPush: componentDefinition.changeDetection === ChangeDetectionStrategy.OnPush,
307307
directiveDefs: directiveTypes ?
308308
() => (typeof directiveTypes === 'function' ? directiveTypes() : directiveTypes)
@@ -660,7 +660,7 @@ export function definePipe<T>(pipeDef: {
660660
name: pipeDef.name,
661661
factory: pipeDef.factory,
662662
pure: pipeDef.pure !== false,
663-
onDestroy: pipeDef.type.prototype.ngOnDestroy || null
663+
onDestroy: (pipeDef.type.prototype as any).ngOnDestroy || null
664664
}) as never;
665665
}
666666

packages/core/src/type.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,6 @@ export function isType(v: any): v is Type<any> {
2222
return typeof v === 'function';
2323
}
2424

25-
export interface Type<T> extends Function { new (...args: any[]): T; }
25+
export interface Type<T> extends Function { prototype: T; }
26+
27+
export interface Constructor<T> extends Type<T> { new (...args: any[]): T; }

packages/core/test/render3/compiler_canonical/small_app_spec.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@ class ToDoAppComponent {
101101

102102
// NON-NORMATIVE
103103
(ToDoAppComponent.ngComponentDef as r3.ComponentDefInternal<any>).directiveDefs = () =>
104-
[ToDoItemComponent.ngComponentDef, (NgForOf as r3.DirectiveType<NgForOf<any>>).ngDirectiveDef];
104+
[ToDoItemComponent.ngComponentDef,
105+
(NgForOf as any as r3.DirectiveType<NgForOf<any>>).ngDirectiveDef];
105106
// /NON-NORMATIVE
106107

107108
@Component({

0 commit comments

Comments
 (0)