From 58d4517898d4831341d2715b881754db8578c32d Mon Sep 17 00:00:00 2001 From: Vitaliy Makogon Date: Wed, 5 Dec 2018 20:47:19 +0200 Subject: [PATCH] feat(common): add strict mode support (#4869) Closes #4848 --- .../app/common/add-nav/add-nav.component.ts | 16 +++++++----- .../+carousel/demos/dynamic/dynamic.ts | 2 +- .../+datepicker/demo-datepicker.module.ts | 12 ++++++--- .../demos/datepicker-demo.component.ts | 18 +++++++------ .../demos/service-nested/service-nested.ts | 6 ++++- .../+rating/demos/dynamic/dynamic.ts | 2 +- .../custom-validation/custom-validation.ts | 7 ++++-- .../+timepicker/demos/dynamic/dynamic.ts | 13 +++++----- .../api-docs/api-doc/api-doc.component.ts | 2 +- demo/src/app/theme/style-manager.ts | 24 +++++++++++++++--- demo/src/app/theme/theme-storage.ts | 11 +++++--- scripts/ci/npm-ng-latest.sh | 2 +- src/pagination/models/index.ts | 1 - src/rating/rating.component.ts | 2 ++ src/typeahead/typeahead.directive.ts | 6 +++++ src/utils/facade/browser.ts | 25 +++++++++---------- tsconfig.json | 2 ++ 17 files changed, 102 insertions(+), 49 deletions(-) diff --git a/demo/src/app/common/add-nav/add-nav.component.ts b/demo/src/app/common/add-nav/add-nav.component.ts index 268b528e5b..73b56f52aa 100644 --- a/demo/src/app/common/add-nav/add-nav.component.ts +++ b/demo/src/app/common/add-nav/add-nav.component.ts @@ -12,15 +12,19 @@ export class AddNavComponent { constructor(@Inject(DOCUMENT) private document: Document) { } - goToSection(event): void { - const item: HTMLElement = event.target; + goToSection(event: Event): void { + const item: HTMLElement = event.target as HTMLElement; if (item.dataset.anchor) { const anchor: string = item.dataset.anchor; - const target: HTMLElement = this.document.getElementById(anchor); - const header: HTMLElement = this.document.getElementById('header'); - const targetPosY: number = target.offsetTop - header.offsetHeight - 6; - window.scrollTo(0, targetPosY); + const target: HTMLElement | null = this.document.getElementById(anchor); + const header: HTMLElement | null = this.document.getElementById('header'); + + if (target && header) { + const targetPosY: number = target.offsetTop - header.offsetHeight - 6; + + window.scrollTo(0, targetPosY); + } } } } diff --git a/demo/src/app/components/+carousel/demos/dynamic/dynamic.ts b/demo/src/app/components/+carousel/demos/dynamic/dynamic.ts index 50d7a6ca21..38fba8cd7f 100644 --- a/demo/src/app/components/+carousel/demos/dynamic/dynamic.ts +++ b/demo/src/app/components/+carousel/demos/dynamic/dynamic.ts @@ -5,7 +5,7 @@ import { Component } from '@angular/core'; templateUrl: './dynamic.html' }) export class DemoCarouselDynamicComponent { - slides = []; + slides: { image: string }[] = []; activeSlideIndex = 0; constructor() { diff --git a/demo/src/app/components/+datepicker/demo-datepicker.module.ts b/demo/src/app/components/+datepicker/demo-datepicker.module.ts index ccf26a5f12..442193702f 100644 --- a/demo/src/app/components/+datepicker/demo-datepicker.module.ts +++ b/demo/src/app/components/+datepicker/demo-datepicker.module.ts @@ -24,7 +24,14 @@ const locales = [ nlBeLocale, nlLocale, plLocale, ptBrLocale, ruLocale, roLocale, skLocale, slLocale, svLocale, thLocale, trLocale, zhCnLocale ]; -locales.forEach((locale: LocaleData) => defineLocale(locale.abbr, locale)); + +locales.forEach((locale: LocaleData) => { + if (!locale.abbr) { + return; + } + + defineLocale(locale.abbr, locale); +}); @NgModule({ declarations: [ @@ -44,5 +51,4 @@ locales.forEach((locale: LocaleData) => defineLocale(locale.abbr, locale)); exports: [DatepickerSectionComponent], entryComponents: [...DEMO_COMPONENTS] }) -export class DemoDatepickerModule { -} +export class DemoDatepickerModule {} diff --git a/demo/src/app/components/+datepicker/demos/datepicker-demo.component.ts b/demo/src/app/components/+datepicker/demos/datepicker-demo.component.ts index a76b6e25a8..732f83b71e 100644 --- a/demo/src/app/components/+datepicker/demos/datepicker-demo.component.ts +++ b/demo/src/app/components/+datepicker/demos/datepicker-demo.component.ts @@ -5,12 +5,12 @@ import { Component } from '@angular/core'; templateUrl: './datepicker-demo.component.html' }) export class DatepickerDemoComponent { - dt: Date = new Date(); - minDate: Date = void 0; + dt: Date | undefined = new Date(); + minDate: Date | undefined = void 0; events: any[]; tomorrow: Date; afterTomorrow: Date; - dateDisabled: { date: Date; mode: string }[]; + dateDisabled: { date: Date; mode: string }[] | undefined; formats: string[] = [ 'DD-MM-YYYY', 'YYYY/MM/DD', @@ -22,7 +22,7 @@ export class DatepickerDemoComponent { formatYear: 'YY', startingDay: 1 }; - private opened: boolean = false; + private opened = false; constructor() { (this.tomorrow = new Date()).setDate(this.tomorrow.getDate() + 1); @@ -54,10 +54,10 @@ export class DatepickerDemoComponent { // todo: implement custom class cases getDayClass(date: any, mode: string): string { if (mode === 'day') { - let dayToCheck = new Date(date).setHours(0, 0, 0, 0); + const dayToCheck = new Date(date).setHours(0, 0, 0, 0); - for (let event of this.events) { - let currentDay = new Date(event.date).setHours(0, 0, 0, 0); + for (const event of this.events) { + const currentDay = new Date(event.date).setHours(0, 0, 0, 0); if (dayToCheck === currentDay) { return event.status; @@ -82,6 +82,10 @@ export class DatepickerDemoComponent { } toggleMin(): void { + if (!this.minDate) { + return; + } + this.dt = new Date(this.minDate.valueOf()); } } diff --git a/demo/src/app/components/+modal/demos/service-nested/service-nested.ts b/demo/src/app/components/+modal/demos/service-nested/service-nested.ts index e573583e3e..8265987970 100644 --- a/demo/src/app/components/+modal/demos/service-nested/service-nested.ts +++ b/demo/src/app/components/+modal/demos/service-nested/service-nested.ts @@ -7,7 +7,7 @@ import { BsModalRef } from 'ngx-bootstrap/modal/bs-modal-ref.service'; templateUrl: './service-nested.html' }) export class DemoModalServiceNestedComponent { - modalRef: BsModalRef; + modalRef: BsModalRef | null; modalRef2: BsModalRef; constructor(private modalService: BsModalService) {} @@ -18,6 +18,10 @@ export class DemoModalServiceNestedComponent { this.modalRef2 = this.modalService.show(template, { class: 'second' }); } closeFirstModal() { + if (!this.modalRef) { + return; + } + this.modalRef.hide(); this.modalRef = null; } diff --git a/demo/src/app/components/+rating/demos/dynamic/dynamic.ts b/demo/src/app/components/+rating/demos/dynamic/dynamic.ts index 8b29204166..9cf494261e 100644 --- a/demo/src/app/components/+rating/demos/dynamic/dynamic.ts +++ b/demo/src/app/components/+rating/demos/dynamic/dynamic.ts @@ -9,7 +9,7 @@ export class DemoRatingDynamicComponent { rate = 7; isReadonly = false; - overStar: number; + overStar: number | undefined; percent: number; hoveringOver(value: number): void { diff --git a/demo/src/app/components/+timepicker/demos/custom-validation/custom-validation.ts b/demo/src/app/components/+timepicker/demos/custom-validation/custom-validation.ts index b16d3ebf95..83c188a56a 100644 --- a/demo/src/app/components/+timepicker/demos/custom-validation/custom-validation.ts +++ b/demo/src/app/components/+timepicker/demos/custom-validation/custom-validation.ts @@ -1,5 +1,5 @@ import { Component } from '@angular/core'; -import { FormControl } from '@angular/forms'; +import { AbstractControl, FormControl } from '@angular/forms'; @Component({ selector: 'demo-timepicker-custom-validation', @@ -8,12 +8,15 @@ import { FormControl } from '@angular/forms'; export class DemoTimepickerCustomValidationComponent { myTime: Date; - ctrl = new FormControl('', (control: FormControl) => { + ctrl = new FormControl('', (control: AbstractControl) => { const value = control.value; + if (!value) { return null; } + const hours = value.getHours(); + if (hours < 11 || hours > 12) { return { outOfRange: true }; } diff --git a/demo/src/app/components/+timepicker/demos/dynamic/dynamic.ts b/demo/src/app/components/+timepicker/demos/dynamic/dynamic.ts index 93ac54ee42..70b4ec798f 100644 --- a/demo/src/app/components/+timepicker/demos/dynamic/dynamic.ts +++ b/demo/src/app/components/+timepicker/demos/dynamic/dynamic.ts @@ -5,18 +5,19 @@ import { Component } from '@angular/core'; templateUrl: './dynamic.html' }) export class DemoTimepickerDynamicComponent { - mytime: Date = new Date(); + mytime: Date | undefined = new Date(); isValid: boolean; update(): void { - let d = new Date(); - d.setHours(14); - d.setMinutes(0); - this.mytime = d; + const time = new Date(); + time.setHours(14); + time.setMinutes(0); + + this.mytime = time; } changed(): void { - console.log('Time changed to: ' + this.mytime); + console.log(`Time changed to: ${this.mytime}`); } clear(): void { diff --git a/demo/src/app/docs/api-docs/api-doc/api-doc.component.ts b/demo/src/app/docs/api-docs/api-doc/api-doc.component.ts index 73fc202ea4..c32a9dbff6 100644 --- a/demo/src/app/docs/api-docs/api-doc/api-doc.component.ts +++ b/demo/src/app/docs/api-docs/api-doc/api-doc.component.ts @@ -56,7 +56,7 @@ export class NgApiDocComponent { * Returns the default value of the given directive input by first looking for it in the matching config service * property. If there is no matching config property, it reads it from the input. */ - defaultInputValue(input: InputDesc): string { + defaultInputValue(input: InputDesc): string | undefined { const configProperty = this.configProperties[input.name]; return configProperty ? configProperty.defaultValue : input.defaultValue; diff --git a/demo/src/app/theme/style-manager.ts b/demo/src/app/theme/style-manager.ts index d7ff0d6024..a0aa4ff94f 100644 --- a/demo/src/app/theme/style-manager.ts +++ b/demo/src/app/theme/style-manager.ts @@ -10,7 +10,13 @@ export class StyleManager { * Set the stylesheet with the specified key. */ setStyle(key: string, href: string) { - getLinkElementForKey(key).setAttribute('href', href); + const linkElement = getLinkElementForKey(key); + + if (!linkElement) { + return; + } + + linkElement.setAttribute('href', href); } /** @@ -18,9 +24,12 @@ export class StyleManager { */ removeStyle(key: string) { const existingLinkElement = getExistingLinkElementByKey(key); - if (existingLinkElement) { - document.head.removeChild(existingLinkElement); + + if (!existingLinkElement || !document.head) { + return; } + + document.head.removeChild(existingLinkElement); } } @@ -29,6 +38,10 @@ function getLinkElementForKey(key: string) { } function getExistingLinkElementByKey(key: string) { + if (!document.head) { + return; + } + return document.head.querySelector(`link[rel="stylesheet"].${getClassNameForKey(key)}`); } @@ -36,6 +49,11 @@ function createLinkElementWithKey(key: string) { const linkEl = document.createElement('link'); linkEl.setAttribute('rel', 'stylesheet'); linkEl.classList.add(getClassNameForKey(key)); + + if (!document.head) { + return; + } + document.head.appendChild(linkEl); return linkEl; diff --git a/demo/src/app/theme/theme-storage.ts b/demo/src/app/theme/theme-storage.ts index 8fa778f3f1..0e824d4e86 100644 --- a/demo/src/app/theme/theme-storage.ts +++ b/demo/src/app/theme/theme-storage.ts @@ -10,11 +10,14 @@ export class ThemeStorage { storeTheme(theme: 'bs3' | 'bs4') { try { window.localStorage[ThemeStorage.storageKey] = theme; - } catch (e) {} + } catch (e) { + return null; + } + this.onThemeUpdate.emit(theme); } - getStoredTheme(): 'bs3' | 'bs4' { + getStoredTheme(): 'bs3' | 'bs4' | null { try { return window.localStorage[ThemeStorage.storageKey] || null; } catch (e) { @@ -25,6 +28,8 @@ export class ThemeStorage { clearStorage() { try { window.localStorage.removeItem(ThemeStorage.storageKey); - } catch (e) {} + } catch (e) { + return null; + } } } diff --git a/scripts/ci/npm-ng-latest.sh b/scripts/ci/npm-ng-latest.sh index f2f96db74f..901fa8ad5b 100755 --- a/scripts/ci/npm-ng-latest.sh +++ b/scripts/ci/npm-ng-latest.sh @@ -16,6 +16,6 @@ npm i @angular/animations@latest \ @angular/service-worker@latest \ @angular-devkit/schematics@latest \ @schematics/angular@latest \ - typescript@3.1.1 \ + typescript@3.1.6 \ tsickle@0.33.0 \ rxjs@6.3 diff --git a/src/pagination/models/index.ts b/src/pagination/models/index.ts index 8d81874e78..c4b6245c27 100644 --- a/src/pagination/models/index.ts +++ b/src/pagination/models/index.ts @@ -10,7 +10,6 @@ export interface ConfigModel { pageBtnClass: string; previousText: string; rotate: boolean; - [key: string]: string | number | boolean; } export interface PagesModel { diff --git a/src/rating/rating.component.ts b/src/rating/rating.component.ts index 42531c2e0d..7cc84be0bb 100644 --- a/src/rating/rating.component.ts +++ b/src/rating/rating.component.ts @@ -51,12 +51,14 @@ export class RatingComponent implements ControlValueAccessor, OnInit { @HostListener('keydown', ['$event']) onKeydown(event: KeyboardEvent): void { + /* tslint:disable-next-line: deprecation */ if ([37, 38, 39, 40].indexOf(event.which) === -1) { return; } event.preventDefault(); event.stopPropagation(); + /* tslint:disable-next-line: deprecation */ const sign = event.which === 38 || event.which === 39 ? 1 : -1; this.rate(this.value + sign); } diff --git a/src/typeahead/typeahead.directive.ts b/src/typeahead/typeahead.directive.ts index 3e66ee91ea..d0ff1afb3c 100644 --- a/src/typeahead/typeahead.directive.ts +++ b/src/typeahead/typeahead.directive.ts @@ -198,6 +198,7 @@ export class TypeaheadDirective implements OnInit, OnDestroy { onChange(e: KeyboardEvent): void { if (this._container) { // esc + /* tslint:disable-next-line: deprecation */ if (e.keyCode === 27) { this.hide(); @@ -205,6 +206,7 @@ export class TypeaheadDirective implements OnInit, OnDestroy { } // up + /* tslint:disable-next-line: deprecation */ if (e.keyCode === 38) { this._container.prevActiveMatch(); @@ -212,6 +214,7 @@ export class TypeaheadDirective implements OnInit, OnDestroy { } // down + /* tslint:disable-next-line: deprecation */ if (e.keyCode === 40) { this._container.nextActiveMatch(); @@ -219,6 +222,7 @@ export class TypeaheadDirective implements OnInit, OnDestroy { } // enter, tab + /* tslint:disable-next-line: deprecation */ if (e.keyCode === 13) { this._container.selectActiveMatch(); @@ -251,6 +255,7 @@ export class TypeaheadDirective implements OnInit, OnDestroy { } // if an item is visible - prevent form submission + /* tslint:disable-next-line: deprecation */ if (e.keyCode === 13) { e.preventDefault(); @@ -258,6 +263,7 @@ export class TypeaheadDirective implements OnInit, OnDestroy { } // if an item is visible - don't change focus + /* tslint:disable-next-line: deprecation */ if (e.keyCode === 9) { e.preventDefault(); this._container.selectActiveMatch(); diff --git a/src/utils/facade/browser.ts b/src/utils/facade/browser.ts index 9c8f6e1181..bd78bbc200 100644 --- a/src/utils/facade/browser.ts +++ b/src/utils/facade/browser.ts @@ -1,4 +1,3 @@ -/*tslint:disable */ /** * @license * Copyright Google Inc. All Rights Reserved. @@ -10,17 +9,17 @@ /** * JS version of browser APIs. This library can only run in the browser. */ -var win = (typeof window !== 'undefined' && window) || {}; +const win = (typeof window !== 'undefined' && window) || {} as any; export { win as window }; -export var document = win.document; -export var location = win.location; -export var gc = win['gc'] ? () => win['gc']() : (): any => null; -export var performance = win['performance'] ? win['performance'] : null; -export const Event = win['Event']; -export const MouseEvent = win['MouseEvent']; -export const KeyboardEvent = win['KeyboardEvent']; -export const EventTarget = win['EventTarget']; -export const History = win['History']; -export const Location = win['Location']; -export const EventListener = win['EventListener']; +export const document = win.document; +export const location = win.location; +export const gc = win.gc ? () => win.gc() : (): any => null; +export const performance = win.performance ? win.performance : null; +export const Event = win.Event; +export const MouseEvent = win.MouseEvent; +export const KeyboardEvent = win.KeyboardEvent; +export const EventTarget = win.EventTarget; +export const History = win.History; +export const Location = win.Location; +export const EventListener = win.EventListener; diff --git a/tsconfig.json b/tsconfig.json index af692bb903..a0efae1c51 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,6 +4,8 @@ "baseUrl": "./", "outDir": "./temp/out-tsc", "sourceMap": true, + "strict": true, + "strictPropertyInitialization": false, "declaration": false, "moduleResolution": "node", "emitDecoratorMetadata": true,