Merge pull request #33361 from BendingBender/p-event

[p-event] Update types to v2.3
This commit is contained in:
Jesse Trinity
2019-02-26 13:24:50 -08:00
committed by GitHub
7 changed files with 393 additions and 48 deletions

View File

@@ -1,17 +1,84 @@
// Type definitions for p-event 1.3
// Type definitions for p-event 2.3
// Project: https://github.com/sindresorhus/p-event#readme
// Definitions by: BendingBender <https://github.com/BendingBender>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.3
import { PCancelable } from 'p-cancelable';
export = pEvent;
declare function pEvent<T, TRest = T>(emitter: pEvent.Emitter<T, TRest>, event: string | symbol, options: MultiArgsOptions<T | TRest>): Promise<Array<T | TRest>>;
declare function pEvent<T>(emitter: pEvent.Emitter<T>, event: string | symbol, filter: FilterFn<T>): Promise<T>;
declare function pEvent<T>(emitter: pEvent.Emitter<T>, event: string | symbol, options?: pEvent.Options<T>): Promise<T>;
/**
* Promisify an event by waiting for it to be emitted.
*
* Returns a `Promise` that is fulfilled when emitter emits an event matching `event`, or rejects if emitter emits
* any of the events defined in the `rejectionEvents` option.
*
* **Note**: `event` is a string for a single event type, for example, `'data'`. To listen on multiple
* events, pass an array of strings, such as `['started', 'stopped']`.
*
* The returned promise has a `.cancel()` method, which when called, removes the event listeners and causes the promise to never be settled.
*
* @param emitter Event emitter object. Should have either a `.on()`/`.addListener()`/`.addEventListener()` and
* `.off()`/`.removeListener()`/`.removeEventListener()` method, like the [Node.js `EventEmitter`](https://nodejs.org/api/events.html) and
* [DOM events](https://developer.mozilla.org/en-US/docs/Web/Events).
* @param event Name of the event or events to listen to. If the same event is defined both here and in
* `rejectionEvents`, this one takes priority.
*/
declare function pEvent<T, TRest = T>(
emitter: pEvent.Emitter<T, TRest>,
event: string | symbol | Array<string | symbol>,
options: pEvent.MultiArgsOptions<T | TRest>
): PCancelable<Array<T | TRest>>;
declare function pEvent<T>(
emitter: pEvent.Emitter<T, any>,
event: string | symbol | Array<string | symbol>,
filter: pEvent.FilterFn<T>
): PCancelable<T>;
declare function pEvent<T>(
emitter: pEvent.Emitter<T, any>,
event: string | symbol | Array<string | symbol>,
options?: pEvent.Options<T>
): PCancelable<T>;
declare namespace pEvent {
interface Emitter<T = any, TRest = T> {
/**
* Wait for multiple event emissions. Returns an array.
*/
function multiple<T, TRest = T>(
emitter: Emitter<T, TRest>,
event: string | symbol | Array<string | symbol>,
options: MultipleMultiArgsOptions<T | TRest>
): PCancelable<Array<Array<T | TRest>>>;
function multiple<T>(
emitter: Emitter<T, any>,
event: string | symbol | Array<string | symbol>,
options: MultipleOptions<T>
): PCancelable<T[]>;
/**
* Returns an [async iterator](http://2ality.com/2016/10/asynchronous-iteration.html) that lets you asynchronously
* iterate over events of `event` emitted from `emitter`. The iterator ends when `emitter` emits an event matching
* any of the events defined in `resolutionEvents`, or rejects if `emitter` emits any of the events defined in
* the `rejectionEvents` option.
*/
function iterator<T, TRest = T>(
emitter: Emitter<T, TRest>,
event: string | symbol | Array<string | symbol>,
options: IteratorMultiArgsOptions<T | TRest>
): AsyncIterableIterator<Array<T | TRest>>;
function iterator<T>(
emitter: Emitter<T, any>,
event: string | symbol | Array<string | symbol>,
filter: FilterFn<T>
): AsyncIterableIterator<T>;
function iterator<T>(
emitter: Emitter<T, any>,
event: string | symbol | Array<string | symbol>,
options?: IteratorOptions<T>
): AsyncIterableIterator<T>;
interface Emitter<T, TRest> {
on?: AddRmListenerFn<T, TRest>;
addListener?: AddRmListenerFn<T, TRest>;
addEventListener?: AddRmListenerFn<T, TRest>;
@@ -20,17 +87,119 @@ declare namespace pEvent {
removeEventListener?: AddRmListenerFn<T, TRest>;
}
type FilterFn<T> = (el: T) => boolean;
interface Options<T> {
rejectionEvents?: string[];
/**
* Events that will reject the promise.
* @default ['error']
*/
rejectionEvents?: Array<string | symbol>;
/**
* By default, the promisified function will only return the first argument from the event callback,
* which works fine for most APIs. This option can be useful for APIs that return multiple arguments
* in the callback. Turning this on will make it return an array of all arguments from the callback,
* instead of just the first argument. This also applies to rejections.
*
* @example
* const pEvent = require('p-event');
* const emitter = require('./some-event-emitter');
*
* (async () => {
* const [foo, bar] = await pEvent(emitter, 'finish', {multiArgs: true});
* })();
*
* @default false
*/
multiArgs?: boolean;
/**
* Time in milliseconds before timing out.
* @default Infinity
*/
timeout?: number;
/**
* Filter function for accepting an event.
*
* @example
* const pEvent = require('p-event');
* const emitter = require('./some-event-emitter');
*
* (async () => {
* const result = await pEvent(emitter, '🦄', value => value > 3);
* // Do something with first 🦄 event with a value greater than 3
* })();
*/
filter?: FilterFn<T>;
}
interface MultiArgsOptions<T> extends Options<T> {
multiArgs: true;
}
interface MultipleOptions<T> extends Options<T> {
/**
* The number of times the event needs to be emitted before the promise resolves.
*/
count: number;
/**
* Whether to resolve the promise immediately. Emitting one of the `rejectionEvents` won't throw an error.
*
* **Note**: The returned array will be mutated when an event is emitted.
*
* @example
* const emitter = new EventEmitter();
*
* const promise = pEvent.multiple(emitter, 'hello', {
* resolveImmediately: true,
* count: Infinity
* });
*
* const result = await promise;
* console.log(result);
* //=> []
*
* emitter.emit('hello', 'Jack');
* console.log(result);
* //=> ['Jack']
*
* emitter.emit('hello', 'Mark');
* console.log(result);
* //=> ['Jack', 'Mark']
*
* // Stops listening
* emitter.emit('error', new Error('😿'));
*
* emitter.emit('hello', 'John');
* console.log(result);
* //=> ['Jack', 'Mark']
*/
resolveImmediately?: boolean;
}
interface MultipleMultiArgsOptions<T> extends MultipleOptions<T> {
multiArgs: true;
}
interface IteratorOptions<T> extends Options<T> {
/**
* Maximum number of events for the iterator before it ends. When the limit is reached, the iterator will be
* marked as `done`. This option is useful to paginate events, for example, fetching 10 events per page.
* @default Infinity
*/
limit?: number;
/**
* Events that will end the iterator.
* @default []
*/
resolutionEvents?: Array<string | symbol>;
}
interface IteratorMultiArgsOptions<T> extends IteratorOptions<T> {
multiArgs: true;
}
}
type AddRmListenerFn<T, TRest> = (event: string | symbol, listener: (arg1: T, ...args: TRest[]) => void) => void;
type FilterFn<T> = (el: T) => boolean;
interface MultiArgsOptions<T> extends pEvent.Options<T> {
multiArgs: true;
}
type AddRmListenerFn<T, TRest> = (
event: string | symbol,
listener: (arg1: T, ...args: TRest[]) => void
) => void;

View File

@@ -1,51 +1,85 @@
/// <reference types="node" />
import pEvent = require('p-event');
import * as events from 'events';
import { EventEmitter } from 'events';
import * as fs from 'fs';
class MyEmitter extends events.EventEmitter {
class NodeEmitter extends EventEmitter {
on(event: 'finish', listener: (num: number, str: string) => void) {
return this;
}
addListener(event: 'finish', listener: (num: number, str: string) => void) {
return this;
}
addEventListener(event: 'finish', listener: (num: number, str: string) => void) {
return this;
}
off(event: 'finish', listener: (num: number, str: string) => void) {
return this;
}
removeListener(event: 'finish', listener: (num: number, str: string) => void) {
return this;
}
removeEventListener(event: 'finish', listener: (num: number, str: string) => void) {
return this;
}
}
class MyDomEmitter implements EventTarget {
addEventListener(type: 'foo', listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void {
}
class DomEmitter implements EventTarget {
addEventListener(
type: 'foo',
listener: EventListenerOrEventListenerObject,
options?: boolean | AddEventListenerOptions
): void {}
dispatchEvent(event: Event): boolean {
return false;
}
removeEventListener(type: 'foo', listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void {
}
removeEventListener(
type: 'foo',
listener: EventListenerOrEventListenerObject,
options?: boolean | AddEventListenerOptions
): void {}
}
pEvent(new MyEmitter(), 'finish')
.then(result => {
console.log(result);
})
.catch(error => {
console.error(error);
});
pEvent(new NodeEmitter(), 'finish'); // $ExpectType PCancelable<number>
pEvent(new NodeEmitter(), '🦄', value => value > 3); // $ExpectType PCancelable<number>
pEvent(new DomEmitter(), 'finish'); // $ExpectType PCancelable<Event>
pEvent(document, 'DOMContentLoaded'); // $ExpectType PCancelable<Event>
pEvent<string>(new MyEmitter(), 'finish').then(result => {
const str: string = result;
});
pEvent(new NodeEmitter(), 'finish', { rejectionEvents: ['error'] }); // $ExpectType PCancelable<number>
pEvent(new NodeEmitter(), 'finish', { timeout: 1 }); // $ExpectType PCancelable<number>
pEvent(new NodeEmitter(), 'finish', { filter: value => value > 3 }); // $ExpectType PCancelable<number>
pEvent(new NodeEmitter(), 'finish', { multiArgs: true }); // $ExpectType PCancelable<(string | number)[]>
pEvent(new MyDomEmitter(), 'finish').then(result => {
const e: Event | undefined = result;
});
pEvent(new NodeEmitter(), 'finish').cancel();
pEvent(document, 'DOMContentLoaded').then(() => {
console.log('😎');
// $ExpectType PCancelable<number[]>
pEvent.multiple(new NodeEmitter(), 'hello', {
count: Infinity,
});
// $ExpectType PCancelable<number[]>
pEvent.multiple(new NodeEmitter(), 'hello', {
resolveImmediately: true,
count: Infinity,
});
// $ExpectType PCancelable<(string | number)[][]>
pEvent.multiple(new NodeEmitter(), 'hello', {
count: Infinity,
multiArgs: true,
});
// $ExpectError
pEvent.multiple(new NodeEmitter(), 'hello', {});
// $ExpectError
pEvent.multiple(new NodeEmitter(), 'hello');
pEvent<string>(new MyEmitter(), 'finish', {multiArgs: true}).then(result => {
const strArr: string[] = result;
});
pEvent.iterator(new NodeEmitter(), 'finish'); // $ExpectType AsyncIterableIterator<number>
pEvent.iterator(new NodeEmitter(), '🦄', value => value > 3); // $ExpectType AsyncIterableIterator<number>
pEvent<number>(new MyEmitter(), '🦄', value => value > 3).then(result => {
const num: number = result;
});
pEvent.iterator(new NodeEmitter(), 'finish', { limit: 1 }); // $ExpectType AsyncIterableIterator<number>
pEvent.iterator(new NodeEmitter(), 'finish', { resolutionEvents: ['finish'] }); // $ExpectType AsyncIterableIterator<number>
pEvent.iterator(new NodeEmitter(), 'finish', { multiArgs: true }); // $ExpectType AsyncIterableIterator<(string | number)[]>
async function getOpenReadStream(file: string) {
const stream = fs.createReadStream(file);
@@ -53,9 +87,24 @@ async function getOpenReadStream(file: string) {
return stream;
}
getOpenReadStream('unicorn.txt')
.then(stream => {
console.log('Is readable:', stream.readable);
stream.pipe(process.stdout);
})
.catch(console.error);
(async () => {
const stream = await getOpenReadStream('unicorn.txt');
stream.pipe(process.stdout);
})().catch(console.error);
(async () => {
try {
const result = await pEvent(new NodeEmitter(), 'finish');
if (result === 1) {
throw new Error('Emitter finished with an error');
}
// `emitter` emitted a `finish` event with an acceptable value
console.log(result);
} catch (error) {
// `emitter` emitted an `error` event or
// emitted a `finish` with 'unwanted result'
console.error(error);
}
})();

View File

@@ -2,7 +2,7 @@
"compilerOptions": {
"module": "commonjs",
"lib": [
"es6",
"es2016",
"dom"
],
"noImplicitAny": true,
@@ -21,4 +21,4 @@
"index.d.ts",
"p-event-tests.ts"
]
}
}

36
types/p-event/v1/index.d.ts vendored Normal file
View File

@@ -0,0 +1,36 @@
// Type definitions for p-event 1.3
// Project: https://github.com/sindresorhus/p-event#readme
// Definitions by: BendingBender <https://github.com/BendingBender>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.3
export = pEvent;
declare function pEvent<T, TRest = T>(emitter: pEvent.Emitter<T, TRest>, event: string | symbol, options: MultiArgsOptions<T | TRest>): Promise<Array<T | TRest>>;
declare function pEvent<T>(emitter: pEvent.Emitter<T>, event: string | symbol, filter: FilterFn<T>): Promise<T>;
declare function pEvent<T>(emitter: pEvent.Emitter<T>, event: string | symbol, options?: pEvent.Options<T>): Promise<T>;
declare namespace pEvent {
interface Emitter<T = any, TRest = T> {
on?: AddRmListenerFn<T, TRest>;
addListener?: AddRmListenerFn<T, TRest>;
addEventListener?: AddRmListenerFn<T, TRest>;
off?: AddRmListenerFn<T, TRest>;
removeListener?: AddRmListenerFn<T, TRest>;
removeEventListener?: AddRmListenerFn<T, TRest>;
}
interface Options<T> {
rejectionEvents?: string[];
multiArgs?: boolean;
timeout?: number;
filter?: FilterFn<T>;
}
}
type AddRmListenerFn<T, TRest> = (event: string | symbol, listener: (arg1: T, ...args: TRest[]) => void) => void;
type FilterFn<T> = (el: T) => boolean;
interface MultiArgsOptions<T> extends pEvent.Options<T> {
multiArgs: true;
}

View File

@@ -0,0 +1,61 @@
/// <reference types="node" />
import pEvent = require('p-event');
import * as events from 'events';
import * as fs from 'fs';
class MyEmitter extends events.EventEmitter {
}
class MyDomEmitter implements EventTarget {
addEventListener(type: 'foo', listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void {
}
dispatchEvent(event: Event): boolean {
return false;
}
removeEventListener(type: 'foo', listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void {
}
}
pEvent(new MyEmitter(), 'finish')
.then(result => {
console.log(result);
})
.catch(error => {
console.error(error);
});
pEvent<string>(new MyEmitter(), 'finish').then(result => {
const str: string = result;
});
pEvent(new MyDomEmitter(), 'finish').then(result => {
const e: Event | undefined = result;
});
pEvent(document, 'DOMContentLoaded').then(() => {
console.log('😎');
});
pEvent<string>(new MyEmitter(), 'finish', {multiArgs: true}).then(result => {
const strArr: string[] = result;
});
pEvent<number>(new MyEmitter(), '🦄', value => value > 3).then(result => {
const num: number = result;
});
async function getOpenReadStream(file: string) {
const stream = fs.createReadStream(file);
await pEvent(stream, 'open');
return stream;
}
getOpenReadStream('unicorn.txt')
.then(stream => {
console.log('Is readable:', stream.readable);
stream.pipe(process.stdout);
})
.catch(console.error);

View File

@@ -0,0 +1,29 @@
{
"compilerOptions": {
"module": "commonjs",
"lib": [
"es6",
"dom"
],
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"strictFunctionTypes": false,
"baseUrl": "../../",
"typeRoots": [
"../../"
],
"paths": {
"p-event": [
"p-event/v1"
]
},
"types": [],
"noEmit": true,
"forceConsistentCasingInFileNames": true
},
"files": [
"index.d.ts",
"p-event-tests.ts"
]
}

View File

@@ -0,0 +1 @@
{ "extends": "dtslint/dt.json" }