From 8b33ee25a555685220328ddbfe36dd4d39cb5949 Mon Sep 17 00:00:00 2001 From: Ben Lesh Date: Fri, 13 Apr 2018 14:49:02 -0700 Subject: [PATCH] fix(rxjs): no longer requires `dom` lib (#3566) Adds interfaces to cover what is used from DOM in `fromEvent` so that types are carried through, but `dom` lib isn not required by default even if you are not using `fromEvent` fixes: #3558 --- compat/observable/FromEventObservable.ts | 12 ++--- src/internal/observable/fromEvent.ts | 62 +++++++++++++----------- 2 files changed, 39 insertions(+), 35 deletions(-) diff --git a/compat/observable/FromEventObservable.ts b/compat/observable/FromEventObservable.ts index 2fc0e64b60..575bde015d 100644 --- a/compat/observable/FromEventObservable.ts +++ b/compat/observable/FromEventObservable.ts @@ -3,16 +3,16 @@ import { EventTargetLike } from 'rxjs/internal-compatibility'; export class FromEventObservable extends Observable { /* tslint:disable:max-line-length */ - static create(target: EventTargetLike, eventName: string): Observable; - static create(target: EventTargetLike, eventName: string, selector: ((...args: any[]) => T)): Observable; - static create(target: EventTargetLike, eventName: string, options: EventListenerOptions): Observable; - static create(target: EventTargetLike, eventName: string, options: EventListenerOptions, selector: ((...args: any[]) => T)): Observable; + static create(target: EventTargetLike, eventName: string): Observable; + static create(target: EventTargetLike, eventName: string, selector: ((...args: any[]) => T)): Observable; + static create(target: EventTargetLike, eventName: string, options: EventListenerOptions): Observable; + static create(target: EventTargetLike, eventName: string, options: EventListenerOptions, selector: ((...args: any[]) => T)): Observable; /* tslint:enable:max-line-length */ - static create(target: EventTargetLike, + static create(target: EventTargetLike, eventName: string, options?: EventListenerOptions | ((...args: any[]) => T), selector?: ((...args: any[]) => T)): Observable { return fromEvent(target, eventName, options as EventListenerOptions, selector); } -} \ No newline at end of file +} diff --git a/src/internal/observable/fromEvent.ts b/src/internal/observable/fromEvent.ts index e1d0e3fc72..6706d93418 100644 --- a/src/internal/observable/fromEvent.ts +++ b/src/internal/observable/fromEvent.ts @@ -13,26 +13,38 @@ export interface NodeStyleEventEmitter { export type NodeEventHandler = (...args: any[]) => void; -export type JQueryStyleEventEmitter = { +export interface JQueryStyleEventEmitter { on: (eventName: string, handler: Function) => void; off: (eventName: string, handler: Function) => void; -}; +} + +export interface HasEventTargetAddRemove { + addEventListener(type: string, listener: ((evt: E) => void) | null, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: string, listener?: ((evt: E) => void) | null, options?: EventListenerOptions | boolean): void; +} + +export type EventTargetLike = HasEventTargetAddRemove | NodeStyleEventEmitter | JQueryStyleEventEmitter; -export type EventTargetLike = EventTarget | NodeStyleEventEmitter | JQueryStyleEventEmitter | NodeList | HTMLCollection; +export type FromEventTarget = EventTargetLike | ArrayLike>; -export type EventListenerOptions = { +export interface EventListenerOptions { capture?: boolean; passive?: boolean; once?: boolean; -} | boolean; +} + +export interface AddEventListenerOptions extends EventListenerOptions { + once?: boolean; + passive?: boolean; +} /* tslint:disable:max-line-length */ -export function fromEvent(target: EventTargetLike, eventName: string): Observable; +export function fromEvent(target: FromEventTarget, eventName: string): Observable; /** @deprecated resultSelector no longer supported, pipe to map instead */ -export function fromEvent(target: EventTargetLike, eventName: string, resultSelector: (...args: any[]) => T): Observable; -export function fromEvent(target: EventTargetLike, eventName: string, options: EventListenerOptions): Observable; +export function fromEvent(target: FromEventTarget, eventName: string, resultSelector: (...args: any[]) => T): Observable; +export function fromEvent(target: FromEventTarget, eventName: string, options: EventListenerOptions): Observable; /** @deprecated resultSelector no longer supported, pipe to map instead */ -export function fromEvent(target: EventTargetLike, eventName: string, options: EventListenerOptions, resultSelector: (...args: any[]) => T): Observable; +export function fromEvent(target: FromEventTarget, eventName: string, options: EventListenerOptions, resultSelector: (...args: any[]) => T): Observable; /* tslint:enable:max-line-length */ /** @@ -138,7 +150,7 @@ export function fromEvent(target: EventTargetLike, eventName: string, options * @see {@link bindNodeCallback} * @see {@link fromEventPattern} * - * @param {EventTargetLike} target The DOM EventTarget, Node.js + * @param {FromEventTarget} target The DOM EventTarget, Node.js * EventEmitter, JQuery-like event target, NodeList or HTMLCollection to attach the event handler to. * @param {string} eventName The event name of interest, being emitted by the * `target`. @@ -147,7 +159,7 @@ export function fromEvent(target: EventTargetLike, eventName: string, options * @name fromEvent */ export function fromEvent( - target: EventTargetLike, + target: FromEventTarget, eventName: string, options?: EventListenerOptions | ((...args: any[]) => T), resultSelector?: ((...args: any[]) => T) @@ -177,18 +189,18 @@ export function fromEvent( }); } -function setupSubscription(sourceObj: EventTargetLike, eventName: string, - handler: Function, subscriber: Subscriber, +function setupSubscription(sourceObj: FromEventTarget, eventName: string, + handler: (...args: any[]) => void, subscriber: Subscriber, options?: EventListenerOptions) { let unsubscribe: () => void; - if (isNodeList(sourceObj) || isHTMLCollection(sourceObj)) { - for (let i = 0, len = sourceObj.length; i < len; i++) { + if (sourceObj && (sourceObj as any).length) { + for (let i = 0, len = (sourceObj as any).length; i < len; i++) { setupSubscription(sourceObj[i], eventName, handler, subscriber, options); } } else if (isEventTarget(sourceObj)) { const source = sourceObj; - sourceObj.addEventListener(eventName, handler as EventListener, options); - unsubscribe = () => source.removeEventListener(eventName, handler as EventListener, options); + sourceObj.addEventListener(eventName, handler, options); + unsubscribe = () => source.removeEventListener(eventName, handler, options); } else if (isJQueryStyleEventEmitter(sourceObj)) { const source = sourceObj; sourceObj.on(eventName, handler); @@ -205,21 +217,13 @@ function setupSubscription(sourceObj: EventTargetLike, eventName: string, } function isNodeStyleEventEmitter(sourceObj: any): sourceObj is NodeStyleEventEmitter { - return !!sourceObj && typeof sourceObj.addListener === 'function' && typeof sourceObj.removeListener === 'function'; + return sourceObj && typeof sourceObj.addListener === 'function' && typeof sourceObj.removeListener === 'function'; } function isJQueryStyleEventEmitter(sourceObj: any): sourceObj is JQueryStyleEventEmitter { - return !!sourceObj && typeof sourceObj.on === 'function' && typeof sourceObj.off === 'function'; -} - -function isNodeList(sourceObj: any): sourceObj is NodeList { - return !!sourceObj && toString.call(sourceObj) === '[object NodeList]'; -} - -function isHTMLCollection(sourceObj: any): sourceObj is HTMLCollection { - return !!sourceObj && toString.call(sourceObj) === '[object HTMLCollection]'; + return sourceObj && typeof sourceObj.on === 'function' && typeof sourceObj.off === 'function'; } -function isEventTarget(sourceObj: any): sourceObj is EventTarget { - return !!sourceObj && typeof sourceObj.addEventListener === 'function' && typeof sourceObj.removeEventListener === 'function'; +function isEventTarget(sourceObj: any): sourceObj is HasEventTargetAddRemove { + return sourceObj && typeof sourceObj.addEventListener === 'function' && typeof sourceObj.removeEventListener === 'function'; }