refactor(ivy): generate ngFactoryDef for injectables (#32433)
With #31953 we moved the factories for components, directives and pipes into a new field called `ngFactoryDef`, however I decided not to do it for injectables, because they needed some extra logic. These changes set up the `ngFactoryDef` for injectables as well. For reference, the extra logic mentioned above is that for injectables we have two code paths: 1. For injectables that don't configure how they should be instantiated, we create a `factory` that proxies to `ngFactoryDef`: ``` // Source @Injectable() class Service {} // Output class Service { static ngInjectableDef = defineInjectable({ factory: () => Service.ngFactoryFn(), }); static ngFactoryFn: (t) => new (t || Service)(); } ``` 2. For injectables that do configure how they're created, we keep the `ngFactoryDef` and generate the factory based on the metadata: ``` // Source @Injectable({ useValue: DEFAULT_IMPL, }) class Service {} // Output export class Service { static ngInjectableDef = defineInjectable({ factory: () => DEFAULT_IMPL, }); static ngFactoryFn: (t) => new (t || Service)(); } ``` PR Close #32433
This commit is contained in:
@ -951,6 +951,37 @@ describe('di', () => {
|
||||
`This will become an error in v10. Please add @Injectable() to the "SubSubClass" class.`);
|
||||
}
|
||||
});
|
||||
|
||||
it('should instantiate correct class when undecorated class extends an injectable', () => {
|
||||
@Injectable()
|
||||
class MyService {
|
||||
id = 1;
|
||||
}
|
||||
|
||||
class MyRootService extends MyService {
|
||||
id = 2;
|
||||
}
|
||||
|
||||
@Component({template: ''})
|
||||
class App {
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [App], providers: [MyRootService]});
|
||||
const warnSpy = spyOn(console, 'warn');
|
||||
const fixture = TestBed.createComponent(App);
|
||||
fixture.detectChanges();
|
||||
|
||||
const provider = TestBed.inject(MyRootService);
|
||||
|
||||
expect(provider instanceof MyRootService).toBe(true);
|
||||
expect(provider.id).toBe(2);
|
||||
|
||||
if (ivyEnabled) {
|
||||
expect(warnSpy).toHaveBeenCalledWith(
|
||||
`DEPRECATED: DI is instantiating a token "MyRootService" that inherits its @Injectable decorator but does not provide one itself.\n` +
|
||||
`This will become an error in v10. Please add @Injectable() to the "MyRootService" class.`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('inject', () => {
|
||||
|
Reference in New Issue
Block a user