Skip to content

Commit

Permalink
refactor(core): ensure compatibility with typescript strict flag (#30993
Browse files Browse the repository at this point in the history
)

As part of FW-1265, the `@angular/core` package is made compatible
with the TypeScript `--strict` flag. This already unveiled a few bugs,
so the strictness flag seems to help with increasing the overall code health.

Read more about the strict flag [here](https://www.typescriptlang.org/docs/handbook/compiler-options.html)

PR Close #30993
  • Loading branch information
devversion authored and mhevery committed Jul 18, 2019
1 parent 78e7fdd commit 2200884
Show file tree
Hide file tree
Showing 29 changed files with 122 additions and 86 deletions.
6 changes: 6 additions & 0 deletions packages/BUILD.bazel
Expand Up @@ -23,6 +23,12 @@ ts_config(
deps = [":tsconfig-build.json"],
)

ts_config(
name = "tsconfig-build-no-strict",
src = "tsconfig-build-no-strict.json",
deps = [":tsconfig-build.json"],
)

exports_files([
"license-banner.txt",
"README.md",
Expand Down
37 changes: 25 additions & 12 deletions packages/core/src/debug/debug_node.ts
Expand Up @@ -440,9 +440,15 @@ class DebugElement__POST_R3__ extends DebugNode__POST_R3__ implements DebugEleme
* @param matches the list of positive matches
* @param elementsOnly whether only elements should be searched
*/
function _queryAllR3(
parentElement: DebugElement, predicate: Predicate<DebugElement>, matches: DebugElement[],
elementsOnly: true): void;
function _queryAllR3(
parentElement: DebugElement, predicate: Predicate<DebugNode>, matches: DebugNode[],
elementsOnly: boolean) {
elementsOnly: false): void;
function _queryAllR3(
parentElement: DebugElement, predicate: Predicate<DebugElement>| Predicate<DebugNode>,
matches: DebugElement[] | DebugNode[], elementsOnly: boolean) {
const context = loadLContext(parentElement.nativeNode) !;
const parentTNode = context.lView[TVIEW].data[context.nodeIndex] as TNode;
_queryNodeChildrenR3(
Expand All @@ -457,11 +463,11 @@ function _queryAllR3(
* @param predicate the predicate to match
* @param matches the list of positive matches
* @param elementsOnly whether only elements should be searched
* @param rootNativeNode the root native node on which prediccate shouold not be matched
* @param rootNativeNode the root native node on which predicate should not be matched
*/
function _queryNodeChildrenR3(
tNode: TNode, lView: LView, predicate: Predicate<DebugNode>, matches: DebugNode[],
elementsOnly: boolean, rootNativeNode: any) {
tNode: TNode, lView: LView, predicate: Predicate<DebugElement>| Predicate<DebugNode>,
matches: DebugElement[] | DebugNode[], elementsOnly: boolean, rootNativeNode: any) {
const nativeNode = getNativeByTNode(tNode, lView);
// For each type of TNode, specific logic is executed.
if (tNode.type === TNodeType.Element || tNode.type === TNodeType.ElementContainer) {
Expand Down Expand Up @@ -535,11 +541,11 @@ function _queryNodeChildrenR3(
* @param predicate the predicate to match
* @param matches the list of positive matches
* @param elementsOnly whether only elements should be searched
* @param rootNativeNode the root native node on which prediccate shouold not be matched
* @param rootNativeNode the root native node on which predicate should not be matched
*/
function _queryNodeChildrenInContainerR3(
lContainer: LContainer, predicate: Predicate<DebugNode>, matches: DebugNode[],
elementsOnly: boolean, rootNativeNode: any) {
lContainer: LContainer, predicate: Predicate<DebugElement>| Predicate<DebugNode>,
matches: DebugElement[] | DebugNode[], elementsOnly: boolean, rootNativeNode: any) {
for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
const childView = lContainer[i];
_queryNodeChildrenR3(
Expand All @@ -554,16 +560,23 @@ function _queryNodeChildrenInContainerR3(
* @param predicate the predicate to match
* @param matches the list of positive matches
* @param elementsOnly whether only elements should be searched
* @param rootNativeNode the root native node on which prediccate shouold not be matched
* @param rootNativeNode the root native node on which predicate should not be matched
*/
function _addQueryMatchR3(
nativeNode: any, predicate: Predicate<DebugNode>, matches: DebugNode[], elementsOnly: boolean,
rootNativeNode: any) {
nativeNode: any, predicate: Predicate<DebugElement>| Predicate<DebugNode>,
matches: DebugElement[] | DebugNode[], elementsOnly: boolean, rootNativeNode: any) {
if (rootNativeNode !== nativeNode) {
const debugNode = getDebugNode(nativeNode);
if (debugNode && (elementsOnly ? debugNode instanceof DebugElement__POST_R3__ : true) &&
predicate(debugNode)) {
if (!debugNode) {
return;
}
// Type of the "predicate and "matches" array are set based on the value of
// the "elementsOnly" parameter. TypeScript is not able to properly infer these
// types with generics, so we manually cast the parameters accordingly.
if (elementsOnly && debugNode instanceof DebugElement__POST_R3__ && predicate(debugNode)) {
matches.push(debugNode);
} else if (!elementsOnly && (predicate as Predicate<DebugNode>)(debugNode)) {
(matches as DebugNode[]).push(debugNode);
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions packages/core/src/di/injectable.ts
Expand Up @@ -92,10 +92,10 @@ export interface InjectableType<T> extends Type<T> { ngInjectableDef: ɵɵInject
* Supports @Injectable() in JIT mode for Render2.
*/
function render2CompileInjectable(
injectableType: InjectableType<any>,
options: {providedIn?: Type<any>| 'root' | null} & InjectableProvider): void {
injectableType: Type<any>,
options?: {providedIn?: Type<any>| 'root' | null} & InjectableProvider): void {
if (options && options.providedIn !== undefined && !getInjectableDef(injectableType)) {
injectableType.ngInjectableDef = ɵɵdefineInjectable({
(injectableType as InjectableType<any>).ngInjectableDef = ɵɵdefineInjectable({
token: injectableType,
providedIn: options.providedIn,
factory: convertInjectableProviderToFactory(injectableType, options),
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/di/injector_compatibility.ts
Expand Up @@ -68,8 +68,8 @@ export function setCurrentInjector(injector: Injector | null | undefined): Injec
* 1. `Injector` should not depend on ivy logic.
* 2. To maintain tree shake-ability we don't want to bring in unnecessary code.
*/
let _injectImplementation: (<T>(token: Type<T>| InjectionToken<T>, flags: InjectFlags) => T | null)|
undefined;
let _injectImplementation:
(<T>(token: Type<T>| InjectionToken<T>, flags?: InjectFlags) => T | null)|undefined;

/**
* Sets the current inject implementation.
Expand Down
5 changes: 3 additions & 2 deletions packages/core/src/di/reflective_provider.ts
Expand Up @@ -180,10 +180,11 @@ export function mergeResolvedReflectiveProviders(
return normalizedProvidersMap;
}

function _normalizeProviders(providers: Provider[], res: Provider[]): Provider[] {
function _normalizeProviders(
providers: Provider[], res: NormalizedProvider[]): NormalizedProvider[] {
providers.forEach(b => {
if (b instanceof Type) {
res.push({provide: b, useClass: b});
res.push({ provide: b, useClass: b } as NormalizedProvider);

} else if (b && typeof b == 'object' && (b as any).provide !== undefined) {
res.push(b as NormalizedProvider);
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/linker/ng_module_factory_registration.ts
Expand Up @@ -50,7 +50,7 @@ export function registerNgModuleType(ngModuleType: NgModuleType) {
imports = imports();
}
if (imports) {
imports.forEach((i: NgModuleType<any>) => registerNgModuleType(i));
imports.forEach(i => registerNgModuleType(i as NgModuleType));
}
}

Expand Down
6 changes: 3 additions & 3 deletions packages/core/src/metadata/ng_module.ts
Expand Up @@ -320,7 +320,7 @@ export const NgModule: NgModuleDecorator = makeDecorator(
* * The `imports` and `exports` options bring in members from other modules, and make
* this module's members available to others.
*/
(type: NgModuleType, meta: NgModule) => SWITCH_COMPILE_NGMODULE(type, meta));
(type: Type<any>, meta: NgModule) => SWITCH_COMPILE_NGMODULE(type, meta));

/**
* @description
Expand All @@ -344,13 +344,13 @@ export const NgModule: NgModuleDecorator = makeDecorator(
*/
export interface DoBootstrap { ngDoBootstrap(appRef: ApplicationRef): void; }

function preR3NgModuleCompile(moduleType: InjectorType<any>, metadata: NgModule): void {
function preR3NgModuleCompile(moduleType: Type<any>, metadata?: NgModule): void {
let imports = (metadata && metadata.imports) || [];
if (metadata && metadata.exports) {
imports = [...imports, metadata.exports];
}

moduleType.ngInjectorDef = ɵɵdefineInjector({
(moduleType as InjectorType<any>).ngInjectorDef = ɵɵdefineInjector({
factory: convertInjectableProviderToFactory(moduleType, {useClass: moduleType}),
providers: metadata && metadata.providers,
imports: imports,
Expand Down
7 changes: 3 additions & 4 deletions packages/core/src/render3/definition.ts
Expand Up @@ -273,7 +273,7 @@ export function ɵɵdefineComponent<T>(componentDefinition: {
pipeDefs: null !, // assigned in noSideEffects
selectors: componentDefinition.selectors,
viewQuery: componentDefinition.viewQuery || null,
features: componentDefinition.features || null,
features: componentDefinition.features as DirectiveDefFeature[] || null,
data: componentDefinition.data || {},
// TODO(misko): convert ViewEncapsulation into const enum so that it can be used directly in the
// next line. Also `None` should be 0 not 2.
Expand Down Expand Up @@ -324,16 +324,15 @@ export function ɵɵsetComponentScope(
def.pipeDefs = () => pipes.map(extractPipeDef);
}

export function extractDirectiveDef(type: DirectiveType<any>& ComponentType<any>):
DirectiveDef<any>|ComponentDef<any> {
export function extractDirectiveDef(type: Type<any>): DirectiveDef<any>|ComponentDef<any> {
const def = getComponentDef(type) || getDirectiveDef(type);
if (ngDevMode && !def) {
throw new Error(`'${type.name}' is neither 'ComponentType' or 'DirectiveType'.`);
}
return def !;
}

export function extractPipeDef(type: PipeType<any>): PipeDef<any> {
export function extractPipeDef(type: Type<any>): PipeDef<any> {
const def = getPipeDef(type);
if (ngDevMode && !def) {
throw new Error(`'${type.name}' is not a 'PipeType'.`);
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/render3/di.ts
Expand Up @@ -556,7 +556,7 @@ export function getNodeInjectable(
const saveLView = getLView();
setTNodeAndViewData(tNode, lData);
try {
value = lData[index] = factory.factory(null, tData, lData, tNode);
value = lData[index] = factory.factory(undefined, tData, lData, tNode);
} finally {
if (factory.injectImpl) setInjectImplementation(previousInjectImplementation);
setIncludeViewProviders(previousIncludeViewProviders);
Expand Down
9 changes: 6 additions & 3 deletions packages/core/src/render3/di_setup.ts
Expand Up @@ -204,7 +204,8 @@ function indexOf(item: any, arr: any[], begin: number, end: number) {
* Use this with `multi` `providers`.
*/
function multiProvidersFactoryResolver(
this: NodeInjectorFactory, _: null, tData: TData, lData: LView, tNode: TElementNode): any[] {
this: NodeInjectorFactory, _: undefined, tData: TData, lData: LView,
tNode: TElementNode): any[] {
return multiResolve(this.multi !, []);
}

Expand All @@ -214,7 +215,8 @@ function multiProvidersFactoryResolver(
* This factory knows how to concatenate itself with the existing `multi` `providers`.
*/
function multiViewProvidersFactoryResolver(
this: NodeInjectorFactory, _: null, tData: TData, lData: LView, tNode: TElementNode): any[] {
this: NodeInjectorFactory, _: undefined, tData: TData, lData: LView,
tNode: TElementNode): any[] {
const factories = this.multi !;
let result: any[];
if (this.providerFactory) {
Expand Down Expand Up @@ -252,7 +254,8 @@ function multiResolve(factories: Array<() => any>, result: any[]): any[] {
*/
function multiFactory(
factoryFn: (
this: NodeInjectorFactory, _: null, tData: TData, lData: LView, tNode: TElementNode) => any,
this: NodeInjectorFactory, _: undefined, tData: TData, lData: LView, tNode: TElementNode) =>
any,
index: number, isViewProvider: boolean, isComponent: boolean,
f: () => any): NodeInjectorFactory {
const factory = new NodeInjectorFactory(factoryFn, isViewProvider, ɵɵdirectiveInject);
Expand Down
5 changes: 2 additions & 3 deletions packages/core/src/render3/instructions/shared.ts
Expand Up @@ -20,7 +20,7 @@ import {diPublicInInjector, getNodeInjectable, getOrCreateNodeInjectorForNode} f
import {throwMultipleComponentError} from '../errors';
import {executeHooks, executePreOrderHooks, registerPreOrderHooks} from '../hooks';
import {ACTIVE_INDEX, CONTAINER_HEADER_OFFSET, LContainer} from '../interfaces/container';
import {ComponentDef, ComponentTemplate, DirectiveDef, DirectiveDefListOrFactory, PipeDefListOrFactory, RenderFlags, ViewQueriesFunction} from '../interfaces/definition';
import {ComponentDef, ComponentTemplate, DirectiveDef, DirectiveDefListOrFactory, FactoryFn, PipeDefListOrFactory, RenderFlags, ViewQueriesFunction} from '../interfaces/definition';
import {INJECTOR_BLOOM_PARENT_SIZE, NodeInjectorFactory} from '../interfaces/injector';
import {AttributeMarker, InitialInputData, InitialInputs, LocalRefExtractor, PropertyAliasValue, PropertyAliases, TAttributes, TContainerNode, TElementContainerNode, TElementNode, TIcuContainerNode, TNode, TNodeFlags, TNodeProviderIndexes, TNodeType, TProjectionNode, TViewNode} from '../interfaces/node';
import {LQueries} from '../interfaces/query';
Expand Down Expand Up @@ -1288,8 +1288,7 @@ export function initNodeFlags(tNode: TNode, index: number, numberOfDirectives: n
}

function baseResolveDirective<T>(
tView: TView, viewData: LView, def: DirectiveDef<T>,
directiveFactory: (t: Type<T>| null) => any) {
tView: TView, viewData: LView, def: DirectiveDef<T>, directiveFactory: FactoryFn<T>) {
tView.data.push(def);
const nodeInjectorFactory = new NodeInjectorFactory(directiveFactory, isComponentDef(def), null);
tView.blueprint.push(nodeInjectorFactory);
Expand Down
8 changes: 4 additions & 4 deletions packages/core/src/render3/interfaces/injector.ts
Expand Up @@ -132,7 +132,7 @@ export class NodeInjectorFactory {
/**
* The inject implementation to be activated when using the factory.
*/
injectImpl: null|(<T>(token: Type<T>|InjectionToken<T>, flags: InjectFlags) => T);
injectImpl: null|(<T>(token: Type<T>|InjectionToken<T>, flags?: InjectFlags) => T);

/**
* Marker set to true during factory invocation to see if we get into recursive loop.
Expand Down Expand Up @@ -216,7 +216,7 @@ export class NodeInjectorFactory {
* Factory to invoke in order to create a new instance.
*/
public factory:
(this: NodeInjectorFactory, _: null,
(this: NodeInjectorFactory, _: undefined,
/**
* array where injectables tokens are stored. This is used in
* case of an error reporting to produce friendlier errors.
Expand All @@ -234,8 +234,8 @@ export class NodeInjectorFactory {
/**
* Set to `true` if the token is declared in `viewProviders` (or if it is component).
*/
isViewProvider: boolean,
injectImplementation: null|(<T>(token: Type<T>|InjectionToken<T>, flags: InjectFlags) => T)) {
isViewProvider: boolean, injectImplementation: null|
(<T>(token: Type<T>|InjectionToken<T>, flags?: InjectFlags) => T)) {
this.canSeeViewProviders = isViewProvider;
this.injectImpl = injectImplementation;
}
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/render3/pipe.ts
Expand Up @@ -166,7 +166,7 @@ export function ɵɵpipeBind4(
*
* @codeGenApi
*/
export function ɵɵpipeBindV(index: number, slotOffset: number, values: any[]): any {
export function ɵɵpipeBindV(index: number, slotOffset: number, values: [any, ...any[]]): any {
const pipeInstance = ɵɵload<PipeTransform>(index);
return unwrapValue(
isPure(index) ? ɵɵpureFunctionV(slotOffset, pipeInstance.transform, values, pipeInstance) :
Expand Down
Expand Up @@ -61,7 +61,7 @@ function findNextInsertionIndex(buffer: HostInstructionsQueue, priority: number)
* Iterates through the host instructions queue (if present within the provided
* context) and executes each queued instruction entry.
*/
export function flushQueue(context: StylingContext): void {
export function flushQueue(this: unknown, context: StylingContext): void {
const buffer = context[StylingIndex.HostInstructionsQueue];
if (buffer) {
for (let i = HostInstructionsQueueIndex.ValuesStartPosition; i < buffer.length;
Expand Down
7 changes: 3 additions & 4 deletions packages/core/src/render3/styling_next/styling_debug.ts
Expand Up @@ -201,7 +201,7 @@ export class NodeStylingDebug implements DebugStyling {
return entries;
}

private _mapValues(fn: (prop: string, value: any, bindingIndex: number|null) => any) {
private _mapValues(fn: (prop: string, value: string|null, bindingIndex: number|null) => any) {
// there is no need to store/track an element instance. The
// element is only used when the styling algorithm attempts to
// style the value (and we mock out the stylingApplyFn anyway).
Expand All @@ -212,9 +212,8 @@ export class NodeStylingDebug implements DebugStyling {
}

const mapFn: ApplyStylingFn =
(renderer: any, element: RElement, prop: string, value: any, bindingIndex: number) => {
fn(prop, value, bindingIndex || null);
};
(renderer: any, element: RElement, prop: string, value: string | null,
bindingIndex?: number | null) => { fn(prop, value, bindingIndex || null); };

const sanitizer = this._isClassBased ? null : (this._sanitizer ||
getCurrentOrLViewSanitizer(this._data as LView));
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/render3/styling_next/util.ts
Expand Up @@ -163,10 +163,10 @@ export function getCurrentOrLViewSanitizer(lView: LView): StyleSanitizeFn|null {
* sanitization.
*/
const sanitizeUsingSanitizerObject: StyleSanitizeFn =
(prop: string, value: string, mode: StyleSanitizeMode) => {
(prop: string, value: string | null, mode?: StyleSanitizeMode) => {
const sanitizer = getCurrentStyleSanitizer() as Sanitizer;
if (sanitizer) {
if (mode & StyleSanitizeMode.SanitizeOnly) {
if (mode !== undefined && mode & StyleSanitizeMode.SanitizeOnly) {
return sanitizer.sanitize(SecurityContext.STYLE, value);
} else {
return true;
Expand Down
12 changes: 7 additions & 5 deletions packages/core/src/util/decorators.ts
Expand Up @@ -46,10 +46,11 @@ export function makeDecorator<T>(
{new (...args: any[]): any; (...args: any[]): any; (...args: any[]): (cls: any) => any;} {
const metaCtor = makeMetadataCtor(props);

function DecoratorFactory(...args: any[]): (cls: Type<T>) => any {
function DecoratorFactory(
this: unknown | typeof DecoratorFactory, ...args: any[]): (cls: Type<T>) => any {
if (this instanceof DecoratorFactory) {
metaCtor.call(this, ...args);
return this;
return this as typeof DecoratorFactory;
}

const annotationInstance = new (DecoratorFactory as any)(...args);
Expand Down Expand Up @@ -79,7 +80,7 @@ export function makeDecorator<T>(
}

function makeMetadataCtor(props?: (...args: any[]) => any): any {
return function ctor(...args: any[]) {
return function ctor(this: any, ...args: any[]) {
if (props) {
const values = props(...args);
for (const propName in values) {
Expand All @@ -92,7 +93,8 @@ function makeMetadataCtor(props?: (...args: any[]) => any): any {
export function makeParamDecorator(
name: string, props?: (...args: any[]) => any, parentClass?: any): any {
const metaCtor = makeMetadataCtor(props);
function ParamDecoratorFactory(...args: any[]): any {
function ParamDecoratorFactory(
this: unknown | typeof ParamDecoratorFactory, ...args: any[]): any {
if (this instanceof ParamDecoratorFactory) {
metaCtor.apply(this, args);
return this;
Expand Down Expand Up @@ -132,7 +134,7 @@ export function makePropDecorator(
additionalProcessing?: (target: any, name: string, ...args: any[]) => void): any {
const metaCtor = makeMetadataCtor(props);

function PropDecoratorFactory(...args: any[]): any {
function PropDecoratorFactory(this: unknown | typeof PropDecoratorFactory, ...args: any[]): any {
if (this instanceof PropDecoratorFactory) {
metaCtor.apply(this, args);
return this;
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/zone/ng_zone.ts
Expand Up @@ -267,7 +267,7 @@ function forkInnerZoneWithAngularBehavior(zone: NgZonePrivate) {


onInvoke: (delegate: ZoneDelegate, current: Zone, target: Zone, callback: Function,
applyThis: any, applyArgs: any[], source: string): any => {
applyThis: any, applyArgs?: any[], source?: string): any => {
try {
onEnter(zone);
return delegate.invoke(target, callback, applyThis, applyArgs, source);
Expand Down
2 changes: 1 addition & 1 deletion packages/core/test/render3/render_util.ts
Expand Up @@ -302,7 +302,7 @@ function toDefs(
types: PipeTypesOrFactory | undefined | null,
mapFn: (type: Type<any>) => PipeDef<any>): PipeDefList|null;
function toDefs(
types: PipeTypesOrFactory | DirectiveTypesOrFactory | undefined | null,
types: Type<any>[] | (() => Type<any>[]) | undefined | null,
mapFn: (type: Type<any>) => PipeDef<any>| DirectiveDef<any>): any {
if (!types) return null;
if (typeof types == 'function') {
Expand Down

0 comments on commit 2200884

Please sign in to comment.