diff --git a/api_guard/dist/types/index.d.ts b/api_guard/dist/types/index.d.ts index be1da4a92b..85a9b012ce 100644 --- a/api_guard/dist/types/index.d.ts +++ b/api_guard/dist/types/index.d.ts @@ -142,9 +142,9 @@ export declare function from>(input: O): Observab export declare function from>(input: O, scheduler: SchedulerLike): Observable>; export declare function fromEvent(target: FromEventTarget, eventName: string): Observable; -export declare function fromEvent(target: FromEventTarget, eventName: string, resultSelector?: (...args: any[]) => T): Observable; -export declare function fromEvent(target: FromEventTarget, eventName: string, options?: EventListenerOptions): Observable; -export declare function fromEvent(target: FromEventTarget, eventName: string, options: EventListenerOptions, resultSelector: (...args: any[]) => T): Observable; +export declare function fromEvent(target: FromEventTarget, eventName: string, resultSelector: (...args: any[]) => T): Observable; +export declare function fromEvent(target: FromEventTarget, eventName: string, options: EventListenerOptions): Observable; +export declare function fromEvent(target: FromEventTarget, eventName: string, options: EventListenerOptions, resultSelector: (...args: any[]) => T): Observable; export declare function fromEventPattern(addHandler: (handler: NodeEventHandler) => any, removeHandler?: (handler: NodeEventHandler, signal?: any) => void): Observable; export declare function fromEventPattern(addHandler: (handler: NodeEventHandler) => any, removeHandler?: (handler: NodeEventHandler, signal?: any) => void, resultSelector?: (...args: any[]) => T): Observable; diff --git a/spec-dtslint/observables/fromEvent-spec.ts b/spec-dtslint/observables/fromEvent-spec.ts index 54b7af3555..738559fda9 100644 --- a/spec-dtslint/observables/fromEvent-spec.ts +++ b/spec-dtslint/observables/fromEvent-spec.ts @@ -1,44 +1,75 @@ import { fromEvent } from 'rxjs'; -import { JQueryStyleEventEmitter } from '../../src/internal/observable/fromEvent'; -import { A, B } from '../helpers'; +import { + HasEventTargetAddRemove, + NodeStyleEventEmitter, + NodeCompatibleEventEmitter, + JQueryStyleEventEmitter +} from '../../src/internal/observable/fromEvent'; +import { B } from '../helpers'; declare const eventTargetSource: EventTarget; it('should support an event target source', () => { + const source: HasEventTargetAddRemove = eventTargetSource; const a = fromEvent(eventTargetSource, "click"); // $ExpectType Observable }); +it('should support an event target source result selector', () => { + const a = fromEvent(eventTargetSource, "click", () => "clunk"); // $ExpectType Observable +}); + declare const documentSource: HTMLDocument; it('should support a document source', () => { + const source: HasEventTargetAddRemove = documentSource; const a = fromEvent(documentSource, "click"); // $ExpectType Observable }); -interface NodeStyleSource { - addListener: (eventName: string | symbol, handler: (...args: any[]) => void) => this; - removeListener: (eventName: string | symbol, handler: (...args: any[]) => void) => this; -}; +it('should support a document source result selector', () => { + const a = fromEvent(documentSource, "click", () => "clunk"); // $ExpectType Observable +}); -declare const nodeStyleSource : NodeStyleSource; +// Pick the parts that will match NodeStyleEventEmitter. If this isn't done, it +// will match JQueryStyleEventEmitter - because of the `on` and `off` methods - +// despite the latter being declared last in the EventTargetLike union. +declare const nodeStyleSource: Pick; it('should support a node-style source', () => { - const a = fromEvent(nodeStyleSource, "something"); // $ExpectType Observable - const b = fromEvent(nodeStyleSource, "something"); // $ExpectType Observable + const source: NodeStyleEventEmitter = nodeStyleSource; + const a = fromEvent(nodeStyleSource, "exit"); // $ExpectType Observable + const b = fromEvent(nodeStyleSource, "exit"); // $ExpectType Observable +}); + +it('should support a node-style source result selector', () => { + const a = fromEvent(nodeStyleSource, "exit", () => "bye"); // $ExpectType Observable }); -declare const nodeCompatibleSource: { - addListener: (eventName: string, handler: (...args: any[]) => void) => void; - removeListener: (eventName: string, handler: (...args: any[]) => void) => void; +const nodeCompatibleSource = { + addListener(eventName: "something", handler: () => void) {}, + removeListener(eventName: "something", handler: () => void) {} }; it('should support a node-compatible source', () => { + const source: NodeCompatibleEventEmitter = nodeCompatibleSource; const a = fromEvent(nodeCompatibleSource, "something"); // $ExpectType Observable const b = fromEvent(nodeCompatibleSource, "something"); // $ExpectType Observable }); -declare const jQueryStyleSource: JQueryStyleEventEmitter; +it('should support a node-compatible source result selector', () => { + const a = fromEvent(nodeCompatibleSource, "something", () => "something else"); // $ExpectType Observable +}); + +const jQueryStyleSource = { + on(eventName: "something", handler: (this: any, b: B) => any) {}, + off(eventName: "something", handler: (this: any, b: B) => any) {} +}; it('should support a jQuery-style source', () => { + const source: JQueryStyleEventEmitter = jQueryStyleSource; const a = fromEvent(jQueryStyleSource, "something"); // $ExpectType Observable const b = fromEvent(jQueryStyleSource, "something"); // $ExpectType Observable }); + +it('should support a jQuery-style source result selector', () => { + const a = fromEvent(jQueryStyleSource, "something", () => "something else"); // $ExpectType Observable +}); diff --git a/src/internal/observable/fromEvent.ts b/src/internal/observable/fromEvent.ts index d17c775d1d..899337c6ea 100644 --- a/src/internal/observable/fromEvent.ts +++ b/src/internal/observable/fromEvent.ts @@ -11,8 +11,8 @@ const eventTargetMethods = ['addEventListener', 'removeEventListener'] as const; const jqueryMethods = ['on', 'off'] as const; export interface NodeStyleEventEmitter { - addListener: (eventName: string | symbol, handler: NodeEventHandler) => this; - removeListener: (eventName: string | symbol, handler: NodeEventHandler) => this; + addListener(eventName: string | symbol, handler: NodeEventHandler): this; + removeListener(eventName: string | symbol, handler: NodeEventHandler): this; } export type NodeEventHandler = (...args: any[]) => void; @@ -21,15 +21,15 @@ export type NodeEventHandler = (...args: any[]) => void; // not use the same arguments or return EventEmitter values // such as React Native export interface NodeCompatibleEventEmitter { - addListener: (eventName: string, handler: NodeEventHandler) => void | {}; - removeListener: (eventName: string, handler: NodeEventHandler) => void | {}; + addListener(eventName: string, handler: NodeEventHandler): void | {}; + removeListener(eventName: string, handler: NodeEventHandler): void | {}; } // Use handler types like those in @types/jquery. See: // https://github.com/DefinitelyTyped/DefinitelyTyped/blob/847731ba1d7fa6db6b911c0e43aa0afe596e7723/types/jquery/misc.d.ts#L6395 export interface JQueryStyleEventEmitter { - on: (eventName: string, handler: (this: TContext, t: T, ...args: any[]) => any) => void; - off: (eventName: string, handler: (this: TContext, t: T, ...args: any[]) => any) => void; + on(eventName: string, handler: (this: TContext, t: T, ...args: any[]) => any): void; + off(eventName: string, handler: (this: TContext, t: T, ...args: any[]) => any): void; } export interface EventListenerObject { @@ -70,11 +70,11 @@ export interface AddEventListenerOptions extends EventListenerOptions { export function fromEvent(target: FromEventTarget, eventName: string): Observable; /** @deprecated resultSelector no longer supported, pipe to map instead */ -export function fromEvent(target: FromEventTarget, eventName: string, resultSelector?: (...args: any[]) => T): Observable; -export function fromEvent(target: FromEventTarget, 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: FromEventTarget, + target: FromEventTarget, eventName: string, options: EventListenerOptions, resultSelector: (...args: any[]) => T @@ -211,7 +211,7 @@ export function fromEvent( } if (resultSelector) { // DEPRECATED PATH - return fromEvent(target, eventName, options as EventListenerOptions | undefined).pipe(mapOneOrManyArgs(resultSelector)); + return fromEvent(target, eventName, options as EventListenerOptions).pipe(mapOneOrManyArgs(resultSelector)); } // Figure out our add and remove methods. In order to do this,