From d8b73e42236fe385e9ba94ef42b80b44598337eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mis=CC=8Cko=20Hevery?= Date: Fri, 24 Mar 2017 09:54:02 -0700 Subject: [PATCH] fix(common): Update types for TypeScript nullability support --- packages/common/src/directives/ng_class.ts | 4 +- .../src/directives/ng_component_outlet.ts | 4 +- packages/common/src/directives/ng_for_of.ts | 8 ++-- packages/common/src/directives/ng_if.ts | 8 ++-- packages/common/src/directives/ng_style.ts | 2 +- .../src/location/hash_location_strategy.ts | 3 +- packages/common/src/location/location.ts | 4 +- .../common/src/location/platform_location.ts | 6 +-- packages/common/src/pipes/async_pipe.ts | 38 ++++++++++--------- packages/common/src/pipes/date_pipe.ts | 4 +- packages/common/src/pipes/i18n_select_pipe.ts | 2 +- packages/common/src/pipes/intl.ts | 17 +++++---- packages/common/src/pipes/number_pipe.ts | 15 ++++---- .../common/test/directives/ng_class_spec.ts | 38 +++++++++---------- .../directives/ng_component_outlet_spec.ts | 16 ++++---- .../common/test/directives/ng_for_spec.ts | 4 +- packages/common/test/directives/ng_if_spec.ts | 2 +- .../common/test/directives/ng_plural_spec.ts | 4 +- .../common/test/directives/ng_style_spec.ts | 2 +- .../common/test/directives/ng_switch_spec.ts | 2 +- .../directives/ng_template_outlet_spec.ts | 6 +-- packages/common/test/pipes/async_pipe_spec.ts | 4 +- packages/common/test/pipes/date_pipe_spec.ts | 2 +- .../test/pipes/i18n_plural_pipe_spec.ts | 2 +- .../common/test/pipes/number_pipe_spec.ts | 12 +++--- packages/common/testing/src/location_mock.ts | 8 ++-- packages/common/tsconfig-build.json | 3 ++ tools/public_api_guard/common/common.d.ts | 21 +++++----- tools/public_api_guard/common/testing.d.ts | 2 +- 29 files changed, 126 insertions(+), 117 deletions(-) diff --git a/packages/common/src/directives/ng_class.ts b/packages/common/src/directives/ng_class.ts index 0d685802e1..73ec957113 100644 --- a/packages/common/src/directives/ng_class.ts +++ b/packages/common/src/directives/ng_class.ts @@ -38,8 +38,8 @@ import {Directive, DoCheck, ElementRef, Input, IterableChanges, IterableDiffer, */ @Directive({selector: '[ngClass]'}) export class NgClass implements DoCheck { - private _iterableDiffer: IterableDiffer; - private _keyValueDiffer: KeyValueDiffer; + private _iterableDiffer: IterableDiffer|null; + private _keyValueDiffer: KeyValueDiffer|null; private _initialClasses: string[] = []; private _rawClass: string[]|Set|{[klass: string]: any}; diff --git a/packages/common/src/directives/ng_component_outlet.ts b/packages/common/src/directives/ng_component_outlet.ts index ae8aa0421c..f924c98ea7 100644 --- a/packages/common/src/directives/ng_component_outlet.ts +++ b/packages/common/src/directives/ng_component_outlet.ts @@ -73,8 +73,8 @@ export class NgComponentOutlet implements OnChanges, OnDestroy { @Input() ngComponentOutletContent: any[][]; @Input() ngComponentOutletNgModuleFactory: NgModuleFactory; - private _componentRef: ComponentRef = null; - private _moduleRef: NgModuleRef = null; + private _componentRef: ComponentRef|null = null; + private _moduleRef: NgModuleRef|null = null; constructor(private _viewContainerRef: ViewContainerRef) {} diff --git a/packages/common/src/directives/ng_for_of.ts b/packages/common/src/directives/ng_for_of.ts index feb9c7b0d6..1441567502 100644 --- a/packages/common/src/directives/ng_for_of.ts +++ b/packages/common/src/directives/ng_for_of.ts @@ -114,7 +114,7 @@ export class NgForOf implements DoCheck, OnChanges { get ngForTrackBy(): TrackByFunction { return this._trackByFn; } - private _differ: IterableDiffer = null; + private _differ: IterableDiffer|null = null; private _trackByFn: TrackByFunction; constructor( @@ -159,13 +159,13 @@ export class NgForOf implements DoCheck, OnChanges { (item: IterableChangeRecord, adjustedPreviousIndex: number, currentIndex: number) => { if (item.previousIndex == null) { const view = this._viewContainer.createEmbeddedView( - this._template, new NgForOfContext(null, this.ngForOf, null, null), currentIndex); - const tuple = new RecordViewTuple(item, view); + this._template, new NgForOfContext(null !, this.ngForOf, -1, -1), currentIndex); + const tuple = new RecordViewTuple(item, view); insertTuples.push(tuple); } else if (currentIndex == null) { this._viewContainer.remove(adjustedPreviousIndex); } else { - const view = this._viewContainer.get(adjustedPreviousIndex); + const view = this._viewContainer.get(adjustedPreviousIndex) !; this._viewContainer.move(view, currentIndex); const tuple = new RecordViewTuple(item, >>view); insertTuples.push(tuple); diff --git a/packages/common/src/directives/ng_if.ts b/packages/common/src/directives/ng_if.ts index 2cb437d562..5e71d31d1f 100644 --- a/packages/common/src/directives/ng_if.ts +++ b/packages/common/src/directives/ng_if.ts @@ -102,10 +102,10 @@ import {Directive, EmbeddedViewRef, Input, TemplateRef, ViewContainerRef} from ' @Directive({selector: '[ngIf]'}) export class NgIf { private _context: NgIfContext = new NgIfContext(); - private _thenTemplateRef: TemplateRef = null; - private _elseTemplateRef: TemplateRef = null; - private _thenViewRef: EmbeddedViewRef = null; - private _elseViewRef: EmbeddedViewRef = null; + private _thenTemplateRef: TemplateRef|null = null; + private _elseTemplateRef: TemplateRef|null = null; + private _thenViewRef: EmbeddedViewRef|null = null; + private _elseViewRef: EmbeddedViewRef|null = null; constructor(private _viewContainer: ViewContainerRef, templateRef: TemplateRef) { this._thenTemplateRef = templateRef; diff --git a/packages/common/src/directives/ng_style.ts b/packages/common/src/directives/ng_style.ts index fafb49e32c..524f482d9f 100644 --- a/packages/common/src/directives/ng_style.ts +++ b/packages/common/src/directives/ng_style.ts @@ -61,7 +61,7 @@ export class NgStyle implements DoCheck { changes.forEachChangedItem((record) => this._setStyle(record.key, record.currentValue)); } - private _setStyle(nameAndUnit: string, value: string|number): void { + private _setStyle(nameAndUnit: string, value: string|number|null|undefined): void { const [name, unit] = nameAndUnit.split('.'); value = value != null && unit ? `${value}${unit}` : value; diff --git a/packages/common/src/location/hash_location_strategy.ts b/packages/common/src/location/hash_location_strategy.ts index 66c5f707bc..70bd23256e 100644 --- a/packages/common/src/location/hash_location_strategy.ts +++ b/packages/common/src/location/hash_location_strategy.ts @@ -66,7 +66,8 @@ export class HashLocationStrategy extends LocationStrategy { } pushState(state: any, title: string, path: string, queryParams: string) { - let url = this.prepareExternalUrl(path + Location.normalizeQueryParams(queryParams)); + let url: string|null = + this.prepareExternalUrl(path + Location.normalizeQueryParams(queryParams)); if (url.length == 0) { url = this._platformLocation.pathname; } diff --git a/packages/common/src/location/location.ts b/packages/common/src/location/location.ts index 3076c48ee1..2ff9133e00 100644 --- a/packages/common/src/location/location.ts +++ b/packages/common/src/location/location.ts @@ -128,8 +128,8 @@ export class Location { * Subscribe to the platform's `popState` events. */ subscribe( - onNext: (value: PopStateEvent) => void, onThrow: (exception: any) => void = null, - onReturn: () => void = null): Object { + onNext: (value: PopStateEvent) => void, onThrow?: ((exception: any) => void)|null, + onReturn?: (() => void)|null): Object { return this._subject.subscribe({next: onNext, error: onThrow, complete: onReturn}); } diff --git a/packages/common/src/location/platform_location.ts b/packages/common/src/location/platform_location.ts index 985935250f..69c3ba25c7 100644 --- a/packages/common/src/location/platform_location.ts +++ b/packages/common/src/location/platform_location.ts @@ -38,9 +38,9 @@ export abstract class PlatformLocation { abstract onPopState(fn: LocationChangeListener): void; abstract onHashChange(fn: LocationChangeListener): void; - get pathname(): string { return null; } - get search(): string { return null; } - get hash(): string { return null; } + abstract get pathname(): string; + abstract get search(): string; + abstract get hash(): string; abstract replaceState(state: any, title: string, url: string): void; diff --git a/packages/common/src/pipes/async_pipe.ts b/packages/common/src/pipes/async_pipe.ts index a64126d575..e53de751d9 100644 --- a/packages/common/src/pipes/async_pipe.ts +++ b/packages/common/src/pipes/async_pipe.ts @@ -8,33 +8,34 @@ import {ChangeDetectorRef, EventEmitter, OnDestroy, Pipe, PipeTransform, WrappedValue, ɵisObservable, ɵisPromise} from '@angular/core'; import {Observable} from 'rxjs/Observable'; - +import {ISubscription} from 'rxjs/Subscription'; import {invalidPipeArgumentError} from './invalid_pipe_argument_error'; interface SubscriptionStrategy { - createSubscription(async: any, updateLatestValue: any): any; - dispose(subscription: any): void; - onDestroy(subscription: any): void; + createSubscription(async: Observable|Promise, updateLatestValue: any): ISubscription + |Promise; + dispose(subscription: ISubscription|Promise): void; + onDestroy(subscription: ISubscription|Promise): void; } class ObservableStrategy implements SubscriptionStrategy { - createSubscription(async: any, updateLatestValue: any): any { + createSubscription(async: Observable, updateLatestValue: any): ISubscription { return async.subscribe({next: updateLatestValue, error: (e: any) => { throw e; }}); } - dispose(subscription: any): void { subscription.unsubscribe(); } + dispose(subscription: ISubscription): void { subscription.unsubscribe(); } - onDestroy(subscription: any): void { subscription.unsubscribe(); } + onDestroy(subscription: ISubscription): void { subscription.unsubscribe(); } } class PromiseStrategy implements SubscriptionStrategy { - createSubscription(async: Promise, updateLatestValue: (v: any) => any): any { + createSubscription(async: Promise, updateLatestValue: (v: any) => any): Promise { return async.then(updateLatestValue, e => { throw e; }); } - dispose(subscription: any): void {} + dispose(subscription: Promise): void {} - onDestroy(subscription: any): void {} + onDestroy(subscription: Promise): void {} } const _promiseStrategy = new PromiseStrategy(); @@ -67,12 +68,12 @@ const _observableStrategy = new ObservableStrategy(); */ @Pipe({name: 'async', pure: false}) export class AsyncPipe implements OnDestroy, PipeTransform { - private _latestValue: Object = null; - private _latestReturnedValue: Object = null; + private _latestValue: any = null; + private _latestReturnedValue: any = null; - private _subscription: Object = null; - private _obj: Observable|Promise|EventEmitter = null; - private _strategy: SubscriptionStrategy = null; + private _subscription: ISubscription|Promise|null = null; + private _obj: Observable|Promise|EventEmitter|null = null; + private _strategy: SubscriptionStrategy = null !; constructor(private _ref: ChangeDetectorRef) {} @@ -82,10 +83,11 @@ export class AsyncPipe implements OnDestroy, PipeTransform { } } + transform(obj: null): null; + transform(obj: undefined): undefined; transform(obj: Observable): T|null; transform(obj: Promise): T|null; - transform(obj: EventEmitter): T|null; - transform(obj: Observable|Promise|EventEmitter): any { + transform(obj: Observable|Promise|null|undefined): any { if (!this._obj) { if (obj) { this._subscribe(obj); @@ -127,7 +129,7 @@ export class AsyncPipe implements OnDestroy, PipeTransform { } private _dispose(): void { - this._strategy.dispose(this._subscription); + this._strategy.dispose(this._subscription !); this._latestValue = null; this._latestReturnedValue = null; this._subscription = null; diff --git a/packages/common/src/pipes/date_pipe.ts b/packages/common/src/pipes/date_pipe.ts index 4a212e0dad..12a5aa7340 100644 --- a/packages/common/src/pipes/date_pipe.ts +++ b/packages/common/src/pipes/date_pipe.ts @@ -100,7 +100,7 @@ export class DatePipe implements PipeTransform { constructor(@Inject(LOCALE_ID) private _locale: string) {} - transform(value: any, pattern: string = 'mediumDate'): string { + transform(value: any, pattern: string = 'mediumDate'): string|null { let date: Date; if (isBlank(value) || value !== value) return null; @@ -130,7 +130,7 @@ export class DatePipe implements PipeTransform { } if (!isDate(date)) { - let match: RegExpMatchArray; + let match: RegExpMatchArray|null; if ((typeof value === 'string') && (match = value.match(ISO8601_DATE_REGEX))) { date = isoStringToDate(match); } else { diff --git a/packages/common/src/pipes/i18n_select_pipe.ts b/packages/common/src/pipes/i18n_select_pipe.ts index 412e8ae735..84a44e4426 100644 --- a/packages/common/src/pipes/i18n_select_pipe.ts +++ b/packages/common/src/pipes/i18n_select_pipe.ts @@ -28,7 +28,7 @@ import {invalidPipeArgumentError} from './invalid_pipe_argument_error'; */ @Pipe({name: 'i18nSelect', pure: true}) export class I18nSelectPipe implements PipeTransform { - transform(value: string, mapping: {[key: string]: string}): string { + transform(value: string|null|undefined, mapping: {[key: string]: string}): string { if (value == null) return ''; if (typeof mapping !== 'object' || typeof value !== 'string') { diff --git a/packages/common/src/pipes/intl.ts b/packages/common/src/pipes/intl.ts index c9bad05171..8309a9a3b8 100644 --- a/packages/common/src/pipes/intl.ts +++ b/packages/common/src/pipes/intl.ts @@ -20,7 +20,7 @@ export class NumberFormatter { minimumIntegerDigits?: number, minimumFractionDigits?: number, maximumFractionDigits?: number, - currency?: string, + currency?: string|null, currencyAsSymbol?: boolean } = {}): string { const options: Intl.NumberFormatOptions = { @@ -31,7 +31,7 @@ export class NumberFormatter { }; if (style == NumberFormatStyle.Currency) { - options.currency = currency; + options.currency = typeof currency == 'string' ? currency : undefined; options.currencyDisplay = currencyAsSymbol ? 'symbol' : 'code'; } return new Intl.NumberFormat(locale, options).format(num); @@ -192,17 +192,18 @@ function dateFormatter(format: string, date: Date, locale: string): string { if (!parts) { parts = []; - let match: RegExpExecArray; + let match: RegExpExecArray|null; DATE_FORMATS_SPLIT.exec(format); - while (format) { - match = DATE_FORMATS_SPLIT.exec(format); + let _format: string|null = format; + while (_format) { + match = DATE_FORMATS_SPLIT.exec(_format); if (match) { parts = parts.concat(match.slice(1)); - format = parts.pop(); + _format = parts.pop() !; } else { - parts.push(format); - format = null; + parts.push(_format); + _format = null; } } diff --git a/packages/common/src/pipes/number_pipe.ts b/packages/common/src/pipes/number_pipe.ts index 221d3c642c..784bc7a768 100644 --- a/packages/common/src/pipes/number_pipe.ts +++ b/packages/common/src/pipes/number_pipe.ts @@ -14,7 +14,8 @@ const _NUMBER_FORMAT_REGEXP = /^(\d+)?\.((\d+)(-(\d+))?)?$/; function formatNumber( pipe: Type, locale: string, value: number | string, style: NumberFormatStyle, - digits: string, currency: string = null, currencyAsSymbol: boolean = false): string { + digits?: string | null, currency: string | null = null, + currencyAsSymbol: boolean = false): string|null { if (value == null) return null; // Convert strings to numbers @@ -23,9 +24,9 @@ function formatNumber( throw invalidPipeArgumentError(pipe, value); } - let minInt: number; - let minFraction: number; - let maxFraction: number; + let minInt: number|undefined = undefined; + let minFraction: number|undefined = undefined; + let maxFraction: number|undefined = undefined; if (style !== NumberFormatStyle.Currency) { // rely on Intl default for currency minInt = 1; @@ -89,7 +90,7 @@ function formatNumber( export class DecimalPipe implements PipeTransform { constructor(@Inject(LOCALE_ID) private _locale: string) {} - transform(value: any, digits: string = null): string { + transform(value: any, digits?: string): string|null { return formatNumber(DecimalPipe, this._locale, value, NumberFormatStyle.Decimal, digits); } } @@ -118,7 +119,7 @@ export class DecimalPipe implements PipeTransform { export class PercentPipe implements PipeTransform { constructor(@Inject(LOCALE_ID) private _locale: string) {} - transform(value: any, digits: string = null): string { + transform(value: any, digits?: string): string|null { return formatNumber(PercentPipe, this._locale, value, NumberFormatStyle.Percent, digits); } } @@ -153,7 +154,7 @@ export class CurrencyPipe implements PipeTransform { transform( value: any, currencyCode: string = 'USD', symbolDisplay: boolean = false, - digits: string = null): string { + digits?: string): string|null { return formatNumber( CurrencyPipe, this._locale, value, NumberFormatStyle.Currency, digits, currencyCode, symbolDisplay); diff --git a/packages/common/test/directives/ng_class_spec.ts b/packages/common/test/directives/ng_class_spec.ts index 66b42e9a71..8d3ecaecc5 100644 --- a/packages/common/test/directives/ng_class_spec.ts +++ b/packages/common/test/directives/ng_class_spec.ts @@ -11,19 +11,19 @@ import {ComponentFixture, TestBed, async} from '@angular/core/testing'; export function main() { describe('binding to CSS class list', () => { - let fixture: ComponentFixture; + let fixture: ComponentFixture|null; function normalizeClassNames(classes: string) { return classes.trim().split(' ').sort().join(' '); } function detectChangesAndExpectClassName(classes: string): void { - fixture.detectChanges(); - let nonNormalizedClassName = fixture.debugElement.children[0].nativeElement.className; + fixture !.detectChanges(); + let nonNormalizedClassName = fixture !.debugElement.children[0].nativeElement.className; expect(normalizeClassNames(nonNormalizedClassName)).toEqual(normalizeClassNames(classes)); } - function getComponent(): TestComponent { return fixture.debugElement.componentInstance; } + function getComponent(): TestComponent { return fixture !.debugElement.componentInstance; } afterEach(() => { fixture = null; }); @@ -74,13 +74,13 @@ export function main() { detectChangesAndExpectClassName('foo'); - objExpr['bar'] = true; + objExpr !['bar'] = true; detectChangesAndExpectClassName('foo bar'); - objExpr['baz'] = true; + objExpr !['baz'] = true; detectChangesAndExpectClassName('foo bar baz'); - delete (objExpr['bar']); + delete (objExpr !['bar']); detectChangesAndExpectClassName('foo baz'); })); @@ -194,7 +194,7 @@ export function main() { it('should throw with descriptive error message when CSS class is not a string', () => { fixture = createTestComponent(`
`); - expect(() => fixture.detectChanges()) + expect(() => fixture !.detectChanges()) .toThrowError( /NgClass can only toggle CSS classes expressed as strings, got \[object Object\]/); }); @@ -266,10 +266,10 @@ export function main() { fixture = createTestComponent('
'); const objExpr = getComponent().objExpr; - objExpr['bar'] = true; + objExpr !['bar'] = true; detectChangesAndExpectClassName('init foo bar'); - objExpr['foo'] = false; + objExpr !['foo'] = false; detectChangesAndExpectClassName('init bar'); getComponent().objExpr = null; @@ -280,10 +280,10 @@ export function main() { fixture = createTestComponent(`
`); const objExpr = getComponent().objExpr; - objExpr['bar'] = true; + objExpr !['bar'] = true; detectChangesAndExpectClassName(`init foo bar`); - objExpr['foo'] = false; + objExpr !['foo'] = false; detectChangesAndExpectClassName(`init bar`); getComponent().objExpr = null; @@ -295,10 +295,10 @@ export function main() { createTestComponent(`
`); const objExpr = getComponent().objExpr; - objExpr['bar'] = true; + objExpr !['bar'] = true; detectChangesAndExpectClassName(`init foo bar`); - objExpr['foo'] = false; + objExpr !['foo'] = false; detectChangesAndExpectClassName(`init bar`); getComponent().objExpr = null; @@ -313,10 +313,10 @@ export function main() { detectChangesAndExpectClassName('init foo baz'); - objExpr['bar'] = true; + objExpr !['bar'] = true; detectChangesAndExpectClassName('init foo baz bar'); - objExpr['foo'] = false; + objExpr !['foo'] = false; detectChangesAndExpectClassName('init baz bar'); getComponent().condition = false; @@ -331,7 +331,7 @@ export function main() { detectChangesAndExpectClassName('init foo'); - cmp.objExpr['bar'] = true; + cmp.objExpr !['bar'] = true; detectChangesAndExpectClassName('init foo bar'); cmp.strExpr = 'baz'; @@ -350,8 +350,8 @@ class TestComponent { items: any[]; arrExpr: string[] = ['foo']; setExpr: Set = new Set(); - objExpr: {[klass: string]: any} = {'foo': true, 'bar': false}; - strExpr = 'foo'; + objExpr: {[klass: string]: any}|null = {'foo': true, 'bar': false}; + strExpr: string|null = 'foo'; constructor() { this.setExpr.add('foo'); } } diff --git a/packages/common/test/directives/ng_component_outlet_spec.ts b/packages/common/test/directives/ng_component_outlet_spec.ts index 736b5c922c..0d897a97c1 100644 --- a/packages/common/test/directives/ng_component_outlet_spec.ts +++ b/packages/common/test/directives/ng_component_outlet_spec.ts @@ -52,7 +52,7 @@ export function main() { fixture.detectChanges(); expect(fixture.nativeElement).toHaveText('foo'); expect(fixture.componentInstance.cmpRef).toBeAnInstanceOf(ComponentRef); - expect(fixture.componentInstance.cmpRef.instance).toBeAnInstanceOf(InjectedComponent); + expect(fixture.componentInstance.cmpRef !.instance).toBeAnInstanceOf(InjectedComponent); })); @@ -100,7 +100,7 @@ export function main() { [{provide: TEST_TOKEN, useValue: uniqueValue}], fixture.componentRef.injector); fixture.detectChanges(); - let cmpRef: ComponentRef = fixture.componentInstance.cmpRef; + let cmpRef: ComponentRef = fixture.componentInstance.cmpRef !; expect(cmpRef).toBeAnInstanceOf(ComponentRef); expect(cmpRef.instance).toBeAnInstanceOf(InjectedComponent); expect(cmpRef.instance.testToken).toBe(uniqueValue); @@ -113,7 +113,7 @@ export function main() { fixture.componentInstance.cmpRef = null; fixture.componentInstance.currentComponent = InjectedComponent; fixture.detectChanges(); - let cmpRef: ComponentRef = fixture.componentInstance.cmpRef; + let cmpRef: ComponentRef = fixture.componentInstance.cmpRef !; expect(cmpRef).toBeAnInstanceOf(ComponentRef); expect(cmpRef.instance).toBeAnInstanceOf(InjectedComponent); expect(cmpRef.instance.testToken).toBeNull(); @@ -169,9 +169,9 @@ export function main() { const moduleRef = fixture.componentInstance.ngComponentOutlet['_moduleRef']; spyOn(moduleRef, 'destroy').and.callThrough(); - expect(moduleRef.destroy).not.toHaveBeenCalled(); + expect(moduleRef !.destroy).not.toHaveBeenCalled(); fixture.destroy(); - expect(moduleRef.destroy).toHaveBeenCalled(); + expect(moduleRef !.destroy).toHaveBeenCalled(); })); it('should not re-create moduleRef when it didn\'t actually change', async(() => { @@ -224,13 +224,13 @@ const TEST_CMP_TEMPLATE = ``; @Component({selector: 'test-cmp', template: TEST_CMP_TEMPLATE}) class TestComponent { - currentComponent: Type; + currentComponent: Type|null; injector: Injector; projectables: any[][]; module: NgModuleFactory; - get cmpRef(): ComponentRef { return this.ngComponentOutlet['_componentRef']; } - set cmpRef(value: ComponentRef) { this.ngComponentOutlet['_componentRef'] = value; } + get cmpRef(): ComponentRef|null { return this.ngComponentOutlet['_componentRef']; } + set cmpRef(value: ComponentRef|null) { this.ngComponentOutlet['_componentRef'] = value; } @ViewChildren(TemplateRef) tplRefs: QueryList>; @ViewChild(NgComponentOutlet) ngComponentOutlet: NgComponentOutlet; diff --git a/packages/common/test/directives/ng_for_spec.ts b/packages/common/test/directives/ng_for_spec.ts index 5a58a10c4f..19ae6c7f41 100644 --- a/packages/common/test/directives/ng_for_spec.ts +++ b/packages/common/test/directives/ng_for_spec.ts @@ -25,7 +25,7 @@ export function main() { expect(fixture.nativeElement).toHaveText(text); } - afterEach(() => { fixture = null; }); + afterEach(() => { fixture = null as any; }); beforeEach(() => { TestBed.configureTestingModule({ @@ -103,7 +103,7 @@ export function main() { detectChangesAndExpectText('1;2;'); - getComponent().items = null; + getComponent().items = null !; detectChangesAndExpectText(''); getComponent().items = [1, 2, 3]; diff --git a/packages/common/test/directives/ng_if_spec.ts b/packages/common/test/directives/ng_if_spec.ts index 43727cc347..a0009bf149 100644 --- a/packages/common/test/directives/ng_if_spec.ts +++ b/packages/common/test/directives/ng_if_spec.ts @@ -19,7 +19,7 @@ export function main() { function getComponent(): TestComponent { return fixture.componentInstance; } - afterEach(() => { fixture = null; }); + afterEach(() => { fixture = null !; }); beforeEach(() => { TestBed.configureTestingModule({ diff --git a/packages/common/test/directives/ng_plural_spec.ts b/packages/common/test/directives/ng_plural_spec.ts index f33580572a..b12904247e 100644 --- a/packages/common/test/directives/ng_plural_spec.ts +++ b/packages/common/test/directives/ng_plural_spec.ts @@ -22,7 +22,7 @@ export function main() { expect(fixture.nativeElement).toHaveText(text); } - afterEach(() => { fixture = null; }); + afterEach(() => { fixture = null !; }); beforeEach(() => { TestBed.configureTestingModule({ @@ -153,7 +153,7 @@ class TestLocalization extends NgLocalization { @Component({selector: 'test-cmp', template: ''}) class TestComponent { - switchValue: number = null; + switchValue: number|null = null; } function createTestComponent(template: string): ComponentFixture { diff --git a/packages/common/test/directives/ng_style_spec.ts b/packages/common/test/directives/ng_style_spec.ts index 5ac554791b..754c05823a 100644 --- a/packages/common/test/directives/ng_style_spec.ts +++ b/packages/common/test/directives/ng_style_spec.ts @@ -20,7 +20,7 @@ export function main() { return expect(fixture.debugElement.children[0].nativeElement); } - afterEach(() => { fixture = null; }); + afterEach(() => { fixture = null !; }); beforeEach(() => { TestBed.configureTestingModule({declarations: [TestComponent], imports: [CommonModule]}); diff --git a/packages/common/test/directives/ng_switch_spec.ts b/packages/common/test/directives/ng_switch_spec.ts index 0c6d9f6c2d..8587b99a52 100644 --- a/packages/common/test/directives/ng_switch_spec.ts +++ b/packages/common/test/directives/ng_switch_spec.ts @@ -22,7 +22,7 @@ export function main() { expect(fixture.nativeElement).toHaveText(text); } - afterEach(() => { fixture = null; }); + afterEach(() => { fixture = null !; }); beforeEach(() => { TestBed.configureTestingModule({ diff --git a/packages/common/test/directives/ng_template_outlet_spec.ts b/packages/common/test/directives/ng_template_outlet_spec.ts index 290bf7d6b1..8f1d25ac95 100644 --- a/packages/common/test/directives/ng_template_outlet_spec.ts +++ b/packages/common/test/directives/ng_template_outlet_spec.ts @@ -22,7 +22,7 @@ export function main() { expect(fixture.debugElement.nativeElement).toHaveText(text); } - afterEach(() => { fixture = null; }); + afterEach(() => { fixture = null as any; }); beforeEach(() => { TestBed.configureTestingModule({ @@ -61,7 +61,7 @@ export function main() { ``; fixture = createTestComponent(template); fixture.detectChanges(); - const refs = fixture.debugElement.children[0].references['refs']; + const refs = fixture.debugElement.children[0].references !['refs']; setTplRef(refs.tplRefs.first); detectChangesAndExpectText('foo'); @@ -77,7 +77,7 @@ export function main() { fixture = createTestComponent(template); fixture.detectChanges(); - const refs = fixture.debugElement.children[0].references['refs']; + const refs = fixture.debugElement.children[0].references !['refs']; setTplRef(refs.tplRefs.first); detectChangesAndExpectText('foo'); diff --git a/packages/common/test/pipes/async_pipe_spec.ts b/packages/common/test/pipes/async_pipe_spec.ts index 84ac8fd257..6dece78987 100644 --- a/packages/common/test/pipes/async_pipe_spec.ts +++ b/packages/common/test/pipes/async_pipe_spec.ts @@ -201,14 +201,14 @@ export function main() { describe('null', () => { it('should return null when given null', () => { - const pipe = new AsyncPipe(null); + const pipe = new AsyncPipe(null as any); expect(pipe.transform(null)).toEqual(null); }); }); describe('other types', () => { it('should throw when given an invalid object', () => { - const pipe = new AsyncPipe(null); + const pipe = new AsyncPipe(null as any); expect(() => pipe.transform('some bogus object')).toThrowError(); }); }); diff --git a/packages/common/test/pipes/date_pipe_spec.ts b/packages/common/test/pipes/date_pipe_spec.ts index 537d2ae37f..e9f456c3a2 100644 --- a/packages/common/test/pipes/date_pipe_spec.ts +++ b/packages/common/test/pipes/date_pipe_spec.ts @@ -197,7 +197,7 @@ export function main() { () => expect(pipe.transform('2017-01-20T19:00:00+0000')).toEqual('Jan 20, 2017')); it('should remove bidi control characters', - () => expect(pipe.transform(date, 'MM/dd/yyyy').length).toEqual(10)); + () => expect(pipe.transform(date, 'MM/dd/yyyy') !.length).toEqual(10)); }); }); } diff --git a/packages/common/test/pipes/i18n_plural_pipe_spec.ts b/packages/common/test/pipes/i18n_plural_pipe_spec.ts index dff70dba6e..fa49cdeb01 100644 --- a/packages/common/test/pipes/i18n_plural_pipe_spec.ts +++ b/packages/common/test/pipes/i18n_plural_pipe_spec.ts @@ -52,7 +52,7 @@ export function main() { }); it('should use "" if value is undefined', () => { - const val = pipe.transform(void(0), mapping); + const val = pipe.transform(void(0) as any, mapping); expect(val).toEqual(''); }); diff --git a/packages/common/test/pipes/number_pipe_spec.ts b/packages/common/test/pipes/number_pipe_spec.ts index 92c6f77e03..85cd251527 100644 --- a/packages/common/test/pipes/number_pipe_spec.ts +++ b/packages/common/test/pipes/number_pipe_spec.ts @@ -51,8 +51,8 @@ export function main() { describe('transform', () => { it('should return correct value for numbers', () => { - expect(normalize(pipe.transform(1.23))).toEqual('123%'); - expect(normalize(pipe.transform(1.2, '.2'))).toEqual('120.00%'); + expect(normalize(pipe.transform(1.23) !)).toEqual('123%'); + expect(normalize(pipe.transform(1.2, '.2') !)).toEqual('120.00%'); }); it('should not support other objects', @@ -69,12 +69,12 @@ export function main() { it('should return correct value for numbers', () => { // In old Chrome, default formatiing for USD is different if (browserDetection.isOldChrome) { - expect(normalize(pipe.transform(123))).toEqual('USD123'); + expect(normalize(pipe.transform(123) !)).toEqual('USD123'); } else { - expect(normalize(pipe.transform(123))).toEqual('USD123.00'); + expect(normalize(pipe.transform(123) !)).toEqual('USD123.00'); } - expect(normalize(pipe.transform(12, 'EUR', false, '.1'))).toEqual('EUR12.0'); - expect(normalize(pipe.transform(5.1234, 'USD', false, '.0-3'))).toEqual('USD5.123'); + expect(normalize(pipe.transform(12, 'EUR', false, '.1') !)).toEqual('EUR12.0'); + expect(normalize(pipe.transform(5.1234, 'USD', false, '.0-3') !)).toEqual('USD5.123'); }); it('should not support other objects', diff --git a/packages/common/testing/src/location_mock.ts b/packages/common/testing/src/location_mock.ts index 9afc3cce80..f52fcc4ecb 100644 --- a/packages/common/testing/src/location_mock.ts +++ b/packages/common/testing/src/location_mock.ts @@ -25,7 +25,7 @@ export class SpyLocation implements Location { /** @internal */ _baseHref: string = ''; /** @internal */ - _platformStrategy: LocationStrategy = null; + _platformStrategy: LocationStrategy = null !; setInitialPath(url: string) { this._history[this._historyIndex].path = url; } @@ -106,12 +106,12 @@ export class SpyLocation implements Location { } subscribe( - onNext: (value: any) => void, onThrow: (error: any) => void = null, - onReturn: () => void = null): Object { + onNext: (value: any) => void, onThrow?: ((error: any) => void)|null, + onReturn?: (() => void)|null): Object { return this._subject.subscribe({next: onNext, error: onThrow, complete: onReturn}); } - normalize(url: string): string { return null; } + normalize(url: string): string { return null !; } } class LocationState { diff --git a/packages/common/tsconfig-build.json b/packages/common/tsconfig-build.json index 8cd3b7541c..873effbeb7 100644 --- a/packages/common/tsconfig-build.json +++ b/packages/common/tsconfig-build.json @@ -4,6 +4,9 @@ "declaration": true, "stripInternal": true, "experimentalDecorators": true, + "strictNullChecks": true, + "noImplicitAny": true, + "noFallthroughCasesInSwitch": true, "module": "es2015", "moduleResolution": "node", "outDir": "../../dist/packages/common", diff --git a/tools/public_api_guard/common/common.d.ts b/tools/public_api_guard/common/common.d.ts index 12b08c4202..9f90b3a0de 100644 --- a/tools/public_api_guard/common/common.d.ts +++ b/tools/public_api_guard/common/common.d.ts @@ -5,9 +5,10 @@ export declare const APP_BASE_HREF: InjectionToken; export declare class AsyncPipe implements OnDestroy, PipeTransform { constructor(_ref: ChangeDetectorRef); ngOnDestroy(): void; - transform(obj: EventEmitter): T | null; transform(obj: Promise): T | null; transform(obj: Observable): T | null; + transform(obj: undefined): undefined; + transform(obj: null): null; } /** @stable */ @@ -17,19 +18,19 @@ export declare class CommonModule { /** @stable */ export declare class CurrencyPipe implements PipeTransform { constructor(_locale: string); - transform(value: any, currencyCode?: string, symbolDisplay?: boolean, digits?: string): string; + transform(value: any, currencyCode?: string, symbolDisplay?: boolean, digits?: string): string | null; } /** @stable */ export declare class DatePipe implements PipeTransform { constructor(_locale: string); - transform(value: any, pattern?: string): string; + transform(value: any, pattern?: string): string | null; } /** @stable */ export declare class DecimalPipe implements PipeTransform { constructor(_locale: string); - transform(value: any, digits?: string): string; + transform(value: any, digits?: string): string | null; } /** @stable */ @@ -55,7 +56,7 @@ export declare class I18nPluralPipe implements PipeTransform { /** @experimental */ export declare class I18nSelectPipe implements PipeTransform { - transform(value: string, mapping: { + transform(value: string | null | undefined, mapping: { [key: string]: string; }): string; } @@ -88,7 +89,7 @@ export declare class Location { path(includeHash?: boolean): string; prepareExternalUrl(url: string): string; replaceState(path: string, query?: string): void; - subscribe(onNext: (value: PopStateEvent) => void, onThrow?: (exception: any) => void, onReturn?: () => void): Object; + subscribe(onNext: (value: PopStateEvent) => void, onThrow?: ((exception: any) => void) | null, onReturn?: (() => void) | null): Object; static joinWithSlash(start: string, end: string): string; static normalizeQueryParams(params: string): string; static stripTrailingSlash(url: string): string; @@ -261,14 +262,14 @@ export declare class PathLocationStrategy extends LocationStrategy { /** @stable */ export declare class PercentPipe implements PipeTransform { constructor(_locale: string); - transform(value: any, digits?: string): string; + transform(value: any, digits?: string): string | null; } /** @stable */ export declare abstract class PlatformLocation { - readonly hash: string; - readonly pathname: string; - readonly search: string; + readonly abstract hash: string; + readonly abstract pathname: string; + readonly abstract search: string; abstract back(): void; abstract forward(): void; abstract getBaseHrefFromDOM(): string; diff --git a/tools/public_api_guard/common/testing.d.ts b/tools/public_api_guard/common/testing.d.ts index ee77b5853e..7270e3a544 100644 --- a/tools/public_api_guard/common/testing.d.ts +++ b/tools/public_api_guard/common/testing.d.ts @@ -31,5 +31,5 @@ export declare class SpyLocation implements Location { setInitialPath(url: string): void; simulateHashChange(pathname: string): void; simulateUrlPop(pathname: string): void; - subscribe(onNext: (value: any) => void, onThrow?: (error: any) => void, onReturn?: () => void): Object; + subscribe(onNext: (value: any) => void, onThrow?: ((error: any) => void) | null, onReturn?: (() => void) | null): Object; }