refactor(angular): enable TS strict

This commit is contained in:
Manu Mtz.-Almeida
2018-07-25 14:29:32 +02:00
parent a5898163b6
commit f1c2c0c1ba
11 changed files with 62 additions and 76 deletions

View File

@ -21,11 +21,12 @@ export class StackController {
ref: enteringRef, ref: enteringRef,
element: (enteringRef && enteringRef.location && enteringRef.location.nativeElement) as HTMLElement, element: (enteringRef && enteringRef.location && enteringRef.location.nativeElement) as HTMLElement,
url: this.getUrl(route), url: this.getUrl(route),
fullpath: document.location.pathname,
deactivatedId: -1 deactivatedId: -1
}; };
} }
getExistingView(activatedRoute: ActivatedRoute): RouteView|null { getExistingView(activatedRoute: ActivatedRoute): RouteView | undefined {
const activatedUrlKey = this.getUrl(activatedRoute); const activatedUrlKey = this.getUrl(activatedRoute);
return this.views.find(vw => vw.url === activatedUrlKey); return this.views.find(vw => vw.url === activatedUrlKey);
} }
@ -74,24 +75,28 @@ export class StackController {
} }
private cleanup() { private cleanup() {
const views = this.views;
this.viewsSnapshot this.viewsSnapshot
.filter(view => !this.views.includes(view)) .filter(view => !views.includes(view))
.forEach(view => destroyView(view)); .forEach(view => destroyView(view));
for (const {element} of this.views) { for (let i = 0; i < views.length - 1; i++) {
const element = views[i].element;
element.setAttribute('aria-hidden', 'true'); element.setAttribute('aria-hidden', 'true');
element.classList.add('ion-page-hidden'); element.classList.add('ion-page-hidden');
} }
this.viewsSnapshot = this.views.slice();
this.viewsSnapshot = views.slice();
} }
getActive(): RouteView | null { getActive(): RouteView | undefined {
return this.views.length > 0 ? this.views[this.views.length - 1] : null; const views = this.views;
return views.length > 0 ? views[views.length - 1] : undefined;
} }
private async transition( private async transition(
enteringView: RouteView, enteringView: RouteView | undefined,
leavingView: RouteView, leavingView: RouteView | undefined,
direction: number, direction: number,
animated: boolean, animated: boolean,
showGoBack: boolean showGoBack: boolean
@ -141,6 +146,7 @@ export function getLastDeactivatedRef(views: RouteView[]) {
export interface RouteView { export interface RouteView {
url: string; url: string;
fullpath: string;
element: HTMLElement; element: HTMLElement;
ref: ComponentRef<any>; ref: ComponentRef<any>;
deactivatedId: number; deactivatedId: number;

View File

@ -41,18 +41,18 @@ export class VirtualScroll {
]); ]);
} }
private nodeRender(el: HTMLElement|null, cell: any, index?: number) { private nodeRender(el: HTMLElement|null, cell: any, index: number) {
if (!el) { if (!el) {
const node = this.itmTmp.viewContainer.createEmbeddedView( const node = this.itmTmp.viewContainer.createEmbeddedView(
this.getComponent(cell.type), this.getComponent(cell.type),
new VirtualContext(null, null, null), { $implicit: null, index },
index index
); );
el = getElement(node); el = getElement(node);
(el as any)['$ionView'] = node; (el as any)['$ionView'] = node;
} }
const node = (el as any)['$ionView']; const node = (el as any)['$ionView'];
const ctx = node.context; const ctx = node.context as VirtualContext;
ctx.$implicit = cell.value; ctx.$implicit = cell.value;
ctx.index = cell.index; ctx.index = cell.index;
node.detectChanges(); node.detectChanges();
@ -65,11 +65,11 @@ export class VirtualScroll {
case 1: return this.hdrTmp.templateRef; case 1: return this.hdrTmp.templateRef;
case 2: return this.ftrTmp.templateRef; case 2: return this.ftrTmp.templateRef;
} }
return null; throw new Error('template for virtual item was not provided');
} }
} }
function getElement(view: EmbeddedViewRef<VirtualContext>): HTMLElement { function getElement(view: EmbeddedViewRef<VirtualContext>): HTMLElement | null {
const rootNodes = view.rootNodes; const rootNodes = view.rootNodes;
for (let i = 0; i < rootNodes.length; i++) { for (let i = 0; i < rootNodes.length; i++) {
if (rootNodes[i].nodeType === 1) { if (rootNodes[i].nodeType === 1) {

View File

@ -1,14 +1,5 @@
export class VirtualContext { export interface VirtualContext {
$implicit: any;
constructor(public $implicit: any, public index: number, public count: number) { } index: number;
get first(): boolean { return this.index === 0; }
get last(): boolean { return this.index === this.count - 1; }
get even(): boolean { return this.index % 2 === 0; }
get odd(): boolean { return !this.even; }
} }

View File

@ -28,7 +28,7 @@ export class AngularFrameworkDelegate implements FrameworkDelegate {
constructor( constructor(
private resolver: ComponentFactoryResolver, private resolver: ComponentFactoryResolver,
private injector: Injector, private injector: Injector,
private location: ViewContainerRef, private location: ViewContainerRef | undefined,
private appRef: ApplicationRef, private appRef: ApplicationRef,
private zone: NgZone, private zone: NgZone,
) {} ) {}
@ -65,7 +65,7 @@ export function attachView(
location: ViewContainerRef | undefined, location: ViewContainerRef | undefined,
appRef: ApplicationRef, appRef: ApplicationRef,
elRefMap: WeakMap<HTMLElement, any>, elRefMap: WeakMap<HTMLElement, any>,
container: any, component: any, params: any, cssClasses: string[] container: any, component: any, params: any, cssClasses: string[] | undefined
) { ) {
const factory = resolver.resolveComponentFactory(component); const factory = resolver.resolveComponentFactory(component);
const childInjector = Injector.create(getProviders(params), injector); const childInjector = Injector.create(getProviders(params), injector);
@ -78,9 +78,11 @@ export function attachView(
if (params) { if (params) {
Object.assign(instance, params); Object.assign(instance, params);
} }
if (cssClasses) {
for (const clazz of cssClasses) { for (const clazz of cssClasses) {
hostElement.classList.add(clazz); hostElement.classList.add(clazz);
} }
}
bindLifecycleEvents(instance, hostElement); bindLifecycleEvents(instance, hostElement);
container.appendChild(hostElement); container.appendChild(hostElement);
@ -103,8 +105,8 @@ const LIFECYCLES = [
export function bindLifecycleEvents(instance: any, element: HTMLElement) { export function bindLifecycleEvents(instance: any, element: HTMLElement) {
LIFECYCLES.forEach(eventName => { LIFECYCLES.forEach(eventName => {
element.addEventListener(eventName, (ev: CustomEvent) => { element.addEventListener(eventName, (ev: any) => {
if (typeof instance[eventName] === 'function') { if (typeof instance[eventName] === 'function' && ev.detail) {
instance[eventName](ev.detail); instance[eventName](ev.detail);
} }
}); });

View File

@ -18,7 +18,7 @@ export class Config {
if (c) { if (c) {
return c.getBoolean(key, fallback); return c.getBoolean(key, fallback);
} }
return null; return false;
} }
getNumber(key: string, fallback?: number): number { getNumber(key: string, fallback?: number): number {
@ -26,7 +26,7 @@ export class Config {
if (c) { if (c) {
return c.getNumber(key, fallback); return c.getNumber(key, fallback);
} }
return null; return 0;
} }
set(key: string, value?: any) { set(key: string, value?: any) {
@ -39,7 +39,7 @@ export class Config {
export const ConfigToken = new InjectionToken<any>('USERCONFIG'); export const ConfigToken = new InjectionToken<any>('USERCONFIG');
function getConfig(): CoreConfig { function getConfig(): CoreConfig | null {
const win: IonicWindow = window as any; const win: IonicWindow = window as any;
if (typeof win !== 'undefined') { if (typeof win !== 'undefined') {
const Ionic = win.Ionic; const Ionic = win.Ionic;

View File

@ -3,7 +3,7 @@ import { Injectable } from '@angular/core';
@Injectable() @Injectable()
export class Events { export class Events {
private c: {[topic: string]: Function[]} = [] as any; private c = new Map<string, Function[]>();
/** /**
* Subscribe to an event topic. Events that get posted to that topic will trigger the provided handler. * Subscribe to an event topic. Events that get posted to that topic will trigger the provided handler.
@ -12,12 +12,11 @@ export class Events {
* @param {function} handler the event handler * @param {function} handler the event handler
*/ */
subscribe(topic: string, ...handlers: Function[]) { subscribe(topic: string, ...handlers: Function[]) {
if (!this.c[topic]) { let topics = this.c.get(topic);
this.c[topic] = []; if (!topics) {
topics = [];
} }
handlers.forEach((handler) => { topics.push(...handlers);
this.c[topic].push(handler);
});
} }
/** /**
@ -28,34 +27,27 @@ export class Events {
* *
* @return true if a handler was removed * @return true if a handler was removed
*/ */
unsubscribe(topic: string, handler: Function = null) { unsubscribe(topic: string, handler?: Function): boolean {
const t = this.c[topic]; if (!handler) {
if (!t) { return this.c.delete(topic);
// Wasn't found, wasn't removed
return false;
} }
if (!handler) { const topics = this.c.get(topic);
// Remove all handlers for this topic if (!topics) {
delete this.c[topic]; return false;
return true;
} }
// We need to find and remove a specific handler // We need to find and remove a specific handler
const i = t.indexOf(handler); const index = topics.indexOf(handler);
if (i < 0) { if (index < 0) {
// Wasn't found, wasn't removed // Wasn't found, wasn't removed
return false; return false;
} }
topics.splice(index, 1);
t.splice(i, 1); if (topics.length === 0) {
this.c.delete(topic);
// If the channel is empty now, remove it from the channel map
if (!t.length) {
delete this.c[topic];
} }
return true; return true;
} }
@ -65,17 +57,12 @@ export class Events {
* @param {string} topic the topic to publish to * @param {string} topic the topic to publish to
* @param {any} eventData the data to send as the event * @param {any} eventData the data to send as the event
*/ */
publish(topic: string, ...args: any[]) { publish(topic: string, ...args: any[]): any[] | null {
const t = this.c[topic]; const topics = this.c.get(topic);
if (!t) { if (!topics) {
return null; return null;
} }
return topics.map((handler => handler(...args)));
const responses: any[] = [];
t.forEach((handler: any) => {
responses.push(handler(...args));
});
return responses;
} }
} }

View File

@ -14,7 +14,7 @@ export class ModalController extends OverlayBaseController<ModalOptions, HTMLIon
super('ion-modal-controller'); super('ion-modal-controller');
} }
create(opts?: ModalOptions): Promise<HTMLIonModalElement> { create(opts: ModalOptions): Promise<HTMLIonModalElement> {
return super.create({ return super.create({
...opts, ...opts,
delegate: this.angularDelegate.create(this.resolver, this.injector) delegate: this.angularDelegate.create(this.resolver, this.injector)

View File

@ -21,17 +21,17 @@ export class NavController {
goForward(url: string | UrlTree, animated?: boolean, extras?: NavigationExtras) { goForward(url: string | UrlTree, animated?: boolean, extras?: NavigationExtras) {
this.setIntent(NavIntent.Forward, animated); this.setIntent(NavIntent.Forward, animated);
return this.router.navigateByUrl(url, extras); return this.router!.navigateByUrl(url, extras);
} }
goBack(url: string | UrlTree, animated?: boolean, extras?: NavigationExtras) { goBack(url: string | UrlTree, animated?: boolean, extras?: NavigationExtras) {
this.setIntent(NavIntent.Back, animated); this.setIntent(NavIntent.Back, animated);
return this.router.navigateByUrl(url, extras); return this.router!.navigateByUrl(url, extras);
} }
goRoot(url: string | UrlTree, animated?: boolean, extras?: NavigationExtras) { goRoot(url: string | UrlTree, animated?: boolean, extras?: NavigationExtras) {
this.setIntent(NavIntent.Root, animated); this.setIntent(NavIntent.Root, animated);
return this.router.navigateByUrl(url, extras); return this.router!.navigateByUrl(url, extras);
} }
setIntent(intent: NavIntent, animated?: boolean) { setIntent(intent: NavIntent, animated?: boolean) {

View File

@ -49,7 +49,7 @@ export class Platform {
readyResolve('cordova'); readyResolve('cordova');
}, {once: true}); }, {once: true});
} else { } else {
readyResolve('dom'); readyResolve!('dom');
} }
} }
@ -169,7 +169,7 @@ export class Platform {
/** /**
* Get the query string parameter * Get the query string parameter
*/ */
getQueryParam(key: string): string { getQueryParam(key: string): string | null {
return readQueryParam(window.location.href, key); return readQueryParam(window.location.href, key);
} }

View File

@ -14,7 +14,7 @@ export class PopoverController extends OverlayBaseController<PopoverOptions, HTM
super('ion-popover-controller'); super('ion-popover-controller');
} }
create(opts?: PopoverOptions): Promise<HTMLIonPopoverElement> { create(opts: PopoverOptions): Promise<HTMLIonPopoverElement> {
return super.create({ return super.create({
...opts, ...opts,
delegate: this.angularDelegate.create(this.resolver, this.injector) delegate: this.angularDelegate.create(this.resolver, this.injector)

View File

@ -1,7 +1,7 @@
{ {
"compilerOptions": { "compilerOptions": {
"alwaysStrict": true, "alwaysStrict": true,
"strict": false, "strict": true,
"allowSyntheticDefaultImports": true, "allowSyntheticDefaultImports": true,
"allowUnreachableCode": false, "allowUnreachableCode": false,
"declaration": true, "declaration": true,