fix(ivy): call factory functions with correct type for derived classes (#30855)
In a derived service class with no decorator (and therefore no factory) of its own, the factory function of the base class will be used instead. Previously this logic had a bug where the factory function would be called with no arguments, which would incorrectly create an instance of the base class. This commit adds logic to call the base class' factory and pass the type of the derived class, which will correctly construct an instance of the derived class using the base class' factory. A test is also added to verify correctness of this behavior. PR Close #30855
This commit is contained in:
parent
0ee09cdd7e
commit
7912db3829
|
@ -438,7 +438,7 @@ function getUndecoratedInjectableFactory(token: Function) {
|
|||
// just instantiates the zero-arg constructor.
|
||||
const inheritedInjectableDef = getInheritedInjectableDef(token);
|
||||
if (inheritedInjectableDef !== null) {
|
||||
return inheritedInjectableDef.factory;
|
||||
return () => inheritedInjectableDef.factory(token as Type<any>);
|
||||
} else {
|
||||
return () => new (token as Type<any>)();
|
||||
}
|
||||
|
|
|
@ -62,7 +62,9 @@ describe('InjectorDef-based createInjector()', () => {
|
|||
static ngInjectableDef = ɵɵdefineInjectable({
|
||||
token: ServiceWithDep,
|
||||
providedIn: null,
|
||||
factory: () => new ServiceWithDep(ɵɵinject(Service)),
|
||||
// ChildService is derived from ServiceWithDep, so the factory function here must do the right
|
||||
// thing and create an instance of the requested type if one is given.
|
||||
factory: (t?: typeof ServiceWithDep) => new (t || ServiceWithDep)(ɵɵinject(Service)),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -163,11 +165,14 @@ describe('InjectorDef-based createInjector()', () => {
|
|||
});
|
||||
}
|
||||
|
||||
class ChildService extends ServiceWithDep {}
|
||||
|
||||
class Module {
|
||||
static ngInjectorDef = ɵɵdefineInjector({
|
||||
factory: () => new Module(),
|
||||
imports: [IntermediateModule],
|
||||
providers: [
|
||||
ChildService,
|
||||
ServiceWithDep,
|
||||
ServiceWithOptionalDep,
|
||||
ServiceWithMultiDep,
|
||||
|
@ -359,6 +364,11 @@ describe('InjectorDef-based createInjector()', () => {
|
|||
expect(instance).toBe(injector.get(ScopedService));
|
||||
});
|
||||
|
||||
it('allows injecting an inherited service', () => {
|
||||
const instance = injector.get(ChildService);
|
||||
expect(instance instanceof ChildService).toBe(true);
|
||||
});
|
||||
|
||||
it('does not create instances of a service not in scope',
|
||||
() => { expect(injector.get(WrongScopeService, null)).toBeNull(); });
|
||||
|
||||
|
|
Loading…
Reference in New Issue