refactor(ivy): fix type of factory functions to allow explicit types (#30855)

Factory functions written by the compiler optionally allow an explicit type
to be passed. If called with this type, an instance of the given type will
be created instead of the type for which the factory was generated. This is
used to power inheritance of Angular types, as if the constructor of a class
is inherited from its superclass, then the factory function of the
superclass must be used (it has all the DI info) to construct an instance of
the derived class.

This commit adjusts typings in a few places to allow factory functions to be
called with this extra type parameter.

PR Close #30855
This commit is contained in:
Alex Rickabaugh 2019-06-04 13:50:48 -07:00 committed by Andrew Kushnir
parent b2937b16c3
commit 0ee09cdd7e
7 changed files with 9 additions and 9 deletions

View File

@ -47,7 +47,7 @@ export interface ɵɵInjectableDef<T> {
/**
* Factory method to execute to create an instance of the injectable.
*/
factory: () => T;
factory: (t?: Type<any>) => T;
/**
* In a case of no explicit injector, a location where the instance of the injectable is stored.

View File

@ -24,7 +24,7 @@ export const angularCoreDiEnv: {[name: string]: Function} = {
'ɵɵgetFactoryOf': getFactoryOf,
};
function getFactoryOf<T>(type: Type<any>): ((type: Type<T>| null) => T)|null {
function getFactoryOf<T>(type: Type<any>): ((type?: Type<T>) => T)|null {
const typeAny = type as any;
const def = getInjectableDef<T>(typeAny) || getInjectorDef<T>(typeAny);
if (!def || def.factory === undefined) {

View File

@ -15,7 +15,7 @@ import {assertDefined, assertEqual} from '../util/assert';
import {getComponentDef, getDirectiveDef, getPipeDef} from './definition';
import {NG_ELEMENT_ID} from './fields';
import {DirectiveDef} from './interfaces/definition';
import {DirectiveDef, FactoryFn} from './interfaces/definition';
import {NO_PARENT_INJECTOR, NodeInjectorFactory, PARENT_INJECTOR, RelativeInjectorLocation, RelativeInjectorLocationFlags, TNODE, isFactory} from './interfaces/injector';
import {AttributeMarker, TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeFlags, TNodeProviderIndexes, TNodeType} from './interfaces/node';
import {DECLARATION_VIEW, INJECTOR, LView, TData, TVIEW, TView, T_HOST} from './interfaces/view';
@ -637,7 +637,7 @@ export class NodeInjector implements Injector {
/**
* @codeGenApi
*/
export function ɵɵgetFactoryOf<T>(type: Type<any>): ((type: Type<T>| null) => T)|null {
export function ɵɵgetFactoryOf<T>(type: Type<any>): FactoryFn<T>|null {
const typeAny = type as any;
const def = getComponentDef<T>(typeAny) || getDirectiveDef<T>(typeAny) ||
getPipeDef<T>(typeAny) || getInjectableDef<T>(typeAny) || getInjectorDef<T>(typeAny);

View File

@ -47,7 +47,7 @@ export type FactoryFn<T> = {
/**
* If no constructor to instantiate is provided, an instance of type T itself is created.
*/
(t: null): T;
(t?: undefined): T;
};
/**

View File

@ -42,7 +42,7 @@ export function ɵɵpipe(index: number, pipeName: string): any {
pipeDef = tView.data[adjustedIndex] as PipeDef<any>;
}
const pipeInstance = pipeDef.factory(null);
const pipeInstance = pipeDef.factory();
store(index, pipeInstance);
return pipeInstance;
}

View File

@ -244,7 +244,7 @@ ivyEnabled && describe('render3 jit', () => {
const pipeDef = (P as any).ngPipeDef as PipeDef<P>;
expect(pipeDef.name).toBe('test-pipe');
expect(pipeDef.pure).toBe(false, 'pipe should not be pure');
expect(pipeDef.factory(null) instanceof P)
expect(pipeDef.factory() instanceof P)
.toBe(true, 'factory() should create an instance of the pipe');
});

View File

@ -837,7 +837,7 @@ export declare function ɵɵenableBindings(): void;
export declare function ɵɵgetCurrentView(): OpaqueViewState;
export declare function ɵɵgetFactoryOf<T>(type: Type<any>): ((type: Type<T> | null) => T) | null;
export declare function ɵɵgetFactoryOf<T>(type: Type<any>): FactoryFn<T> | null;
export declare function ɵɵgetInheritedFactory<T>(type: Type<any>): (type: Type<T>) => T;
@ -868,7 +868,7 @@ export declare function ɵɵinject<T>(token: Type<T> | InjectionToken<T>): T;
export declare function ɵɵinject<T>(token: Type<T> | InjectionToken<T>, flags?: InjectFlags): T | null;
export interface ɵɵInjectableDef<T> {
factory: () => T;
factory: (t?: Type<any>) => T;
providedIn: InjectorType<any> | 'root' | 'any' | null;
token: unknown;
value: T | undefined;