Skip to content

Commit

Permalink
Tighten up multiArgs TypeScript type constraints (#22)
Browse files Browse the repository at this point in the history
  • Loading branch information
AaronFriel authored and sindresorhus committed Mar 13, 2019
1 parent a8578a3 commit c8bddfa
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 42 deletions.
77 changes: 38 additions & 39 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
/// <reference lib="esnext"/>

export type AddRemoveListener<FirstArgumentType, RestArgumentsType> = (
export type AddRemoveListener<Arguments extends unknown[]> = (
event: string | symbol,
listener: (
firstArgument: FirstArgumentType,
...rest: RestArgumentsType[]
...args: Arguments,
) => void
) => void;

export interface Emitter<EmittedType, EmittedTypeRest> {
on?: AddRemoveListener<EmittedType, EmittedTypeRest>;
addListener?: AddRemoveListener<EmittedType, EmittedTypeRest>;
addEventListener?: AddRemoveListener<EmittedType, EmittedTypeRest>;
off?: AddRemoveListener<EmittedType, EmittedTypeRest>;
removeListener?: AddRemoveListener<EmittedType, EmittedTypeRest>;
removeEventListener?: AddRemoveListener<EmittedType, EmittedTypeRest>;
export interface Emitter<EmittedType extends unknown[]> {
on?: AddRemoveListener<EmittedType>;
addListener?: AddRemoveListener<EmittedType>;
addEventListener?: AddRemoveListener<EmittedType>;
off?: AddRemoveListener<EmittedType>;
removeListener?: AddRemoveListener<EmittedType>;
removeEventListener?: AddRemoveListener<EmittedType>;
}

export type FilterFunction<ElementType> = (element: ElementType) => boolean;
export type FilterFunction<ElementType extends unknown[]> = (...args: ElementType) => boolean;

export interface CancelablePromise<ResolveType> extends Promise<ResolveType> {
cancel(): void;
Expand All @@ -30,58 +29,58 @@ export interface CancelablePromise<ResolveType> extends Promise<ResolveType> {
* @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. **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']`.
* @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. The returned promise has a `.cancel()` method, which when called, removes the event listeners and causes the promise to never be settled.
*/
declare function pEvent<EmittedType, EmittedTypeRest = EmittedType>(
emitter: Emitter<EmittedType, EmittedTypeRest>,
declare function pEvent<EmittedType extends unknown[]>(
emitter: Emitter<EmittedType>,
event: string | symbol | (string | symbol)[],
options: MultiArgumentsOptions<EmittedType | EmittedTypeRest>
): CancelablePromise<(EmittedType | EmittedTypeRest)[]>;
options: MultiArgumentsOptions<EmittedType>
): CancelablePromise<EmittedType>;
declare function pEvent<EmittedType>(
emitter: Emitter<EmittedType, unknown>,
emitter: Emitter<[EmittedType]>,
event: string | symbol | (string | symbol)[],
filter: FilterFunction<EmittedType>
filter: FilterFunction<[EmittedType]>
): CancelablePromise<EmittedType>;
declare function pEvent<EmittedType>(
emitter: Emitter<EmittedType, unknown>,
emitter: Emitter<[EmittedType]>,
event: string | symbol | (string | symbol)[],
options?: Options<EmittedType>
options?: Options<[EmittedType]>
): CancelablePromise<EmittedType>;

export default pEvent;

/**
* Wait for multiple event emissions. Returns an array.
*/
export function multiple<EmittedType, EmittedTypeRest = EmittedType>(
emitter: Emitter<EmittedType, EmittedTypeRest>,
export function multiple<EmittedType extends unknown[]>(
emitter: Emitter<EmittedType>,
event: string | symbol | (string | symbol)[],
options: MultipleMultiArgumentsOptions<EmittedType | EmittedTypeRest>
): CancelablePromise<(EmittedType | EmittedTypeRest)[][]>;
options: MultipleMultiArgumentsOptions<EmittedType>
): CancelablePromise<EmittedType[]>;
export function multiple<EmittedType>(
emitter: Emitter<EmittedType, unknown>,
emitter: Emitter<[EmittedType]>,
event: string | symbol | (string | symbol)[],
options: MultipleOptions<EmittedType>
options: MultipleOptions<[EmittedType]>
): CancelablePromise<EmittedType[]>;

/**
* @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.
*/
export function iterator<EmittedType, EmittedTypeRest = EmittedType>(
emitter: Emitter<EmittedType, EmittedTypeRest>,
export function iterator<EmittedType extends unknown[]>(
emitter: Emitter<EmittedType>,
event: string | symbol | (string | symbol)[],
options: IteratorMultiArgumentsOptions<EmittedType | EmittedTypeRest>
): AsyncIterableIterator<(EmittedType | EmittedTypeRest)[]>;
options: IteratorMultiArgumentsOptions<EmittedType>
): AsyncIterableIterator<EmittedType>;
export function iterator<EmittedType>(
emitter: Emitter<EmittedType, unknown>,
emitter: Emitter<[EmittedType]>,
event: string | symbol | (string | symbol)[],
filter: FilterFunction<EmittedType>
filter: FilterFunction<[EmittedType]>
): AsyncIterableIterator<EmittedType>;
export function iterator<EmittedType>(
emitter: Emitter<EmittedType, unknown>,
emitter: Emitter<[EmittedType]>,
event: string | symbol | (string | symbol)[],
options?: IteratorOptions<EmittedType>
options?: IteratorOptions<[EmittedType]>
): AsyncIterableIterator<EmittedType>;

export interface Options<EmittedType> {
export interface Options<EmittedType extends unknown[]> {
/**
* Events that will reject the promise.
*
Expand Down Expand Up @@ -128,11 +127,11 @@ export interface Options<EmittedType> {
readonly filter?: FilterFunction<EmittedType>;
}

export interface MultiArgumentsOptions<EmittedType> extends Options<EmittedType> {
export interface MultiArgumentsOptions<EmittedType extends unknown[]> extends Options<EmittedType> {
readonly multiArgs: true;
}

export interface MultipleOptions<EmittedType> extends Options<EmittedType> {
export interface MultipleOptions<EmittedType extends unknown[]> extends Options<EmittedType> {
/**
* The number of times the event needs to be emitted before the promise resolves.
*/
Expand Down Expand Up @@ -174,11 +173,11 @@ export interface MultipleOptions<EmittedType> extends Options<EmittedType> {
readonly resolveImmediately?: boolean;
}

export interface MultipleMultiArgumentsOptions<EmittedType> extends MultipleOptions<EmittedType> {
export interface MultipleMultiArgumentsOptions<EmittedType extends unknown[]> extends MultipleOptions<EmittedType> {
readonly multiArgs: true;
}

export interface IteratorOptions<EmittedType> extends Options<EmittedType> {
export interface IteratorOptions<EmittedType extends unknown[]> extends Options<EmittedType> {
/**
* 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.
*
Expand All @@ -194,7 +193,7 @@ export interface IteratorOptions<EmittedType> extends Options<EmittedType> {
resolutionEvents?: (string | symbol)[];
}

export interface IteratorMultiArgumentsOptions<EmittedType>
export interface IteratorMultiArgumentsOptions<EmittedType extends unknown[]>
extends IteratorOptions<EmittedType> {
multiArgs: true;
}
6 changes: 3 additions & 3 deletions index.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ expectType<CancelablePromise<number>>(
expectType<CancelablePromise<number>>(
pEvent(new NodeEmitter(), 'finish', {filter: value => value > 3})
);
expectType<CancelablePromise<(string | number)[]>>(
expectType<CancelablePromise<[number, string]>>(
pEvent(new NodeEmitter(), 'finish', {multiArgs: true})
);

Expand All @@ -90,7 +90,7 @@ expectType<CancelablePromise<number[]>>(
count: Infinity
})
);
expectType<CancelablePromise<(string | number)[][]>>(
expectType<CancelablePromise<[number, string][]>>(
multiple(new NodeEmitter(), 'hello', {
count: Infinity,
multiArgs: true
Expand All @@ -110,7 +110,7 @@ expectType<AsyncIterableIterator<number>>(
expectType<AsyncIterableIterator<number>>(
iterator(new NodeEmitter(), 'finish', {resolutionEvents: ['finish']})
);
expectType<AsyncIterableIterator<(string | number)[]>>(
expectType<AsyncIterableIterator<[number, string]>>(
iterator(new NodeEmitter(), 'finish', {multiArgs: true})
);

Expand Down

0 comments on commit c8bddfa

Please sign in to comment.