fix(ivy): support sub-class services that only inherit @Injectable
(#30388)
In View engine it is possible to instantiate a service that that has no `@Injectable` decorator as long as it satisfies one of: 1) It has no dependencies and so a constructor with no parameters. This is already supported in Ivy. 2) It has no constructor of its own and sub-classes a service which has dependencies but has its own `@Injectable` decorator. This second scenario was broken in Ivy. In Ivy, previous to this commit, if a class to be instantiated did not have its own `@Injectable` decorator and did not provide a constructor of its own, then it would be created using `new` with no arguments - i.e. falling back to the first scenario. After this commit Ivy correctly uses the `ngInjectableDef` inherited from the super-class to provide the `factory` for instantiating the sub-class. FW-1314 PR Close #30388
This commit is contained in:

committed by
Jason Aden

parent
35c1750fcc
commit
1a0e500eea
@ -10,7 +10,7 @@ import {CommonModule} from '@angular/common';
|
||||
import {Attribute, ChangeDetectorRef, Component, Directive, ElementRef, EventEmitter, Host, HostBinding, INJECTOR, Inject, Injectable, Injector, Input, LOCALE_ID, Optional, Output, Pipe, PipeTransform, Self, SkipSelf, TemplateRef, ViewChild, ViewContainerRef, forwardRef} from '@angular/core';
|
||||
import {ViewRef} from '@angular/core/src/render3/view_ref';
|
||||
import {TestBed} from '@angular/core/testing';
|
||||
import {onlyInIvy} from '@angular/private/testing';
|
||||
import {ivyEnabled, onlyInIvy} from '@angular/private/testing';
|
||||
|
||||
describe('di', () => {
|
||||
describe('no dependencies', () => {
|
||||
@ -370,7 +370,7 @@ describe('di', () => {
|
||||
<div dirA #dir="dirA">{{ dir.dirB.value }}</div>
|
||||
</ng-template>
|
||||
</div>
|
||||
|
||||
|
||||
<div dirB value="insertion">
|
||||
<div structuralDir [tmp]="foo"></div>
|
||||
<!-- insertion point -->
|
||||
@ -858,6 +858,40 @@ describe('di', () => {
|
||||
const divElement = fixture.nativeElement.querySelector('div');
|
||||
expect(divElement.textContent).toEqual('MyService');
|
||||
});
|
||||
|
||||
it('should support sub-classes with no @Injectable decorator', () => {
|
||||
@Injectable()
|
||||
class Dependency {
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
class SuperClass {
|
||||
constructor(public dep: Dependency) {}
|
||||
}
|
||||
|
||||
// Note, no @Injectable decorators for these two classes
|
||||
class SubClass extends SuperClass {}
|
||||
class SubSubClass extends SubClass {}
|
||||
|
||||
@Component({template: ''})
|
||||
class MyComp {
|
||||
constructor(public myService: SuperClass) {}
|
||||
}
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [MyComp],
|
||||
providers: [{provide: SuperClass, useClass: SubSubClass}, Dependency]
|
||||
});
|
||||
|
||||
const warnSpy = spyOn(console, 'warn');
|
||||
const fixture = TestBed.createComponent(MyComp);
|
||||
expect(fixture.componentInstance.myService.dep instanceof Dependency).toBe(true);
|
||||
|
||||
if (ivyEnabled) {
|
||||
expect(warnSpy).toHaveBeenCalledWith(
|
||||
`DEPRECATED: DI is instantiating a token "SubSubClass" that inherits its @Injectable decorator but does not provide one itself.\n` +
|
||||
`This will become an error in v10. Please add @Injectable() to the "SubSubClass" class.`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('inject', () => {
|
||||
|
Reference in New Issue
Block a user