Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tighten up multiArgs TypeScript type constraints #22

Merged
merged 2 commits into from
Mar 13, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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