evnty 1.5.2 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Evnty
2
2
 
3
- 0-Deps, simple, fast, for browser and node js anonymous event library.
3
+ 0-Deps, simple, fast, for browser and node js reactive anonymous event library.
4
4
 
5
5
  [![Coverage Status][codecov-image]][codecov-url]
6
6
  [![Github Build Status][github-image]][github-url]
@@ -10,31 +10,48 @@
10
10
 
11
11
  ## Table of Contents
12
12
 
13
+ - [Motivation](#motivation)
13
14
  - [Features](#features)
14
15
  - [Platform Support](#platform-support)
15
16
  - [Installing](#installing)
17
+ - [Usage](#usage)
18
+ - [createEvent](#createevent)
19
+ - [filter](#filter)
20
+ - [map](#map)
21
+ - [reduce](#reduce)
22
+ - [debounce](#debounce)
23
+ - [merge](#merge)
24
+ - [createInterval](#createInterval)
16
25
  - [Examples](#examples)
17
- - [Roadmap](#roadmap)
26
+ - [Migration](#migration)
18
27
  - [License](#license)
19
28
 
29
+ ## Motivation
30
+
31
+ In traditional event handling in TypeScript, events are often represented as strings, and there's no easy way to apply functional transformations like filtering or mapping directly on the event data. This approach lacks type safety, and chaining operations require additional boilerplate, making the code verbose and less maintainable.
32
+
33
+ The proposed library introduces a robust `Event` abstraction that encapsulates event data and provides a suite of functional methods like `map`, `filter`, `reduce`, `debounce`, etc., allowing for a more declarative and type-safe approach to event handling. This design facilitates method chaining and composition, making the code more readable and maintainable. For instance, it allows developers to create new events by transforming or filtering existing ones, thus promoting code reusability and modularity.
34
+
35
+ #### Benefits:
36
+
37
+ - Type Safety: The Event abstraction enforces type safety, helping catch potential errors at compile-time.
38
+ - Method Chaining: Functional methods can be chained together to form complex event handling logic with less code.
39
+ - Event Composition: Events can be merged, filtered, or transformed to create new events, promoting code modularity and reusability.
40
+ - Reduced Boilerplate: The library reduces the boilerplate code required to set up complex event handling logic, making the codebase cleaner and easier to manage.
41
+
20
42
  ## Features
21
43
 
22
44
  - Supports ESM and CommonJS
23
45
  - Promises support
24
- - Full-featured typeScript support
46
+ - Full-featured TypeScript support
25
47
  - Browser & Workers environment compatibility
26
48
  - Performance eventemitter3/eventemitter2/event-emitter/events/native node/native browser
27
49
 
28
- ## Roadmap
29
-
30
- - Namespaces/Wildcards
31
- - Times To Listen (TTL)
32
-
33
- ## Browser Support
50
+ ## Platform Support
34
51
 
35
52
  | ![NodeJS][node-image] | ![Chrome][chrome-image] | ![Firefox][firefox-image] | ![Safari][safari-image] | ![Opera][opera-image] | ![Edge][edge-image] |
36
- | ----------------------- | ----------------------- | ------------------------- | ----------------------- | --------------------- | ------------------- |
37
- | Latest ✔ | Latest ✔ | Latest ✔ | Latest ✔ | Latest ✔ | Latest ✔ |
53
+ | --------------------- | ----------------------- | ------------------------- | ----------------------- | --------------------- | ------------------- |
54
+ | Latest ✔ | Latest ✔ | Latest ✔ | Latest ✔ | Latest ✔ | Latest ✔ |
38
55
 
39
56
  [node-image]: https://raw.github.com/alrra/browser-logos/main/src/node.js/node.js_48x48.png?1
40
57
  [chrome-image]: https://raw.github.com/alrra/browser-logos/main/src/chrome/chrome_48x48.png?1
@@ -45,6 +62,12 @@
45
62
 
46
63
  ## Installing
47
64
 
65
+ Using pnpm:
66
+
67
+ ```bash
68
+ pnpm add evnty
69
+ ```
70
+
48
71
  Using yarn:
49
72
 
50
73
  ```bash
@@ -57,20 +80,111 @@ Using npm:
57
80
  npm install evnty
58
81
  ```
59
82
 
83
+ ## Usage
84
+
85
+ ### createEvent
86
+
87
+ Creates a new event instance.
88
+
89
+ ```ts
90
+ import { createEvent, Event } from 'evnty';
91
+
92
+ type ClickEvent = { x: number; y: number; button: number };
93
+ const clickEvent = createEvent<ClickEvent>();
94
+
95
+ type KeyPressEvent = { key: string };
96
+ const keyPressEvent = createEvent<KeyPressEvent>();
97
+
98
+ type ChangeEvent = { target: HTMLInputElement };
99
+ const changeEvent = createEvent<ChangeEvent>();
100
+ document.querySelector('input').addEventListener('change', changeEvent);
101
+ ```
102
+
103
+ ### filter
104
+
105
+ Returns a new event that will only be triggered once the provided filter function returns `true`.
106
+ Supports predicate type guard function and filter function as a more concise variant.
107
+
108
+ ```ts
109
+ import { Predicate } from 'evnty';
110
+
111
+ type SpacePressEvent = KeyPressEvent & { key: 'Space' };
112
+ type LeftClickEvent = ClickEvent & { button: 1 };
113
+
114
+ const spacePressPredicate: Predicate<KeyPressEvent, SpacePressEvent> = (keyPressEvent): keyPressEvent is SpacePressEvent => keyPressEvent.key === 'Space';
115
+ // event type is inferred from the predicate function
116
+ const spacePressPredicatedEvent = keyPressEvent.filter(spacePredicate);
117
+ // event type is inferred from the explicitly specified type
118
+ const spacePressFilteredEvent = keyPressEvent.filter<SpacePressEvent>(({ key }) => key === 'Space');
119
+
120
+ const leftClickPredicate: Predicate<ClickEvent, LeftClickEvent> = (mouseClickEvent): mouseClickEvent is LeftClickEvent => mouseClickEvent.button === 1;
121
+ // event type is inferred from the predicate function
122
+ const leftClickPredicatedEvent = clickEvent.filter(leftClickPredicate);
123
+ // event type is inferred from the explicitly specified type
124
+ const leftClickFilteredEvent = keyPressEvent.filter<LeftClickEvent>(({ button }) => button === 1);
125
+ ```
126
+
127
+ ### map
128
+
129
+ Returns a new event that maps the values of this event using the provided mapper function.
130
+
131
+ ```ts
132
+ const point = { x: 100, y: 100 };
133
+ const distanceClickEvent = clickEvent.map((click) => (click.x - point.x) ** 2 + (click.y - point.y) ** 2);
134
+ const lowerCaseKeyPressEvent = keyPressEvent.map(({ key }) => key.toLowerCase());
135
+ const trimmedChangeEvent = changeEvent.map((event) => event.target.value.trim());
136
+ ```
137
+
138
+ ### reduce
139
+
140
+ Returns a new event that reduces the emitted values using the provided reducer function.
141
+
142
+ ```ts
143
+ const rightClickCountEvent = clickEvent.reduce((result, click) => (click.button === 2 ? result + 1 : result), 0);
144
+ ```
145
+
146
+ ### debounce
147
+
148
+ Returns a new debounced event that will not fire until a certain amount of time has passed since the last time it was triggered.
149
+
150
+ ```ts
151
+ const searchEvent = changeEvent.debounce(500);
152
+ ```
153
+
154
+ ### merge
155
+
156
+ Merges multiple events into a single event.
157
+
158
+ ```ts
159
+ import { merge } from 'evnty';
160
+
161
+ const inputEvent = merge(clickEvent, keyPressEvent);
162
+ ```
163
+
164
+ ### createInterval
165
+
166
+ Creates an event that triggers at a specified interval.
167
+
168
+ ```ts
169
+ import { createInterval } from 'evnty';
170
+
171
+ const everySecondEvent = createInterval(1000);
172
+ ```
173
+
60
174
  ## Examples
61
175
 
62
176
  ```js
63
- import createEvent, { Event, once } from 'evnty';
177
+ import createEvent, { Event } from 'evnty';
64
178
 
65
179
  // Creates a click event
66
180
  type Click = { button: string };
67
- const clickEvent = createEvent<[Click]>();
181
+ const clickEvent = createEvent<Click>();
68
182
  const handleClick = ({ button }: Click) => console.log('Clicked button is', button);
69
183
  const unsubscribeClick = clickEvent.on(handleClick);
70
184
 
71
185
  // Creates a key press event
72
186
  type KeyPress = { key: string };
73
- const keyPressEvent = createEvent<[KeyPress]>();
187
+ const keyPressEvent = createEvent<KeyPress>();
74
188
  const handleKeyPress = ({ key }: KeyPress) => console.log('Key pressed', key);
75
189
  const unsubscribeKeyPress = keyPressEvent.on(handleKeyPress);
76
190
 
@@ -88,7 +202,7 @@ leftClickEvent.on(handleLeftClick);
88
202
  // Will press Enter after one second
89
203
  setTimeout(keyPressEvent, 1000, { key: 'Enter' });
90
204
  // Waits once the first Enter key press event occurs
91
- await once(keyPressEvent.first(({ key }) => key === 'Enter'));
205
+ await keyPressEvent.first(({ key }) => key === 'Enter').onceAsync();
92
206
 
93
207
  keyPressEvent({ key: 'W' });
94
208
  keyPressEvent({ key: 'A' });
@@ -105,11 +219,20 @@ unsubscribeClick();
105
219
  leftClickEvent.off(handleLeftClick);
106
220
 
107
221
  // Unsubscribe key press listener once first Esc key press occur
108
- unsubscribeKeyPress.after(() => once(keyPressEvent.first(({ key }) => key === 'Esc')));
222
+ unsubscribeKeyPress.after(() => keyPressEvent
223
+ .first(({ key }) => key === 'Esc')
224
+ .onceAsync()
225
+ );
109
226
  // Press Esc to unsubscribe key press listener
110
227
  keyPressEvent({ key: 'Esc' });
111
228
  ```
112
229
 
230
+ ## Migration
231
+
232
+ ### From v1 to v2
233
+
234
+ A breaking change has been made: events no longer accept a list of arguments. Now, each event accepts a single argument, so simply wrap your arguments in an object. This decision was taken to leverage the benefits of predicate type guards.
235
+
113
236
  ## License
114
237
 
115
238
  License [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0)
package/build/index.cjs CHANGED
@@ -18,8 +18,11 @@ _export(exports, {
18
18
  Event: function() {
19
19
  return Event;
20
20
  },
21
- once: function() {
22
- return once;
21
+ merge: function() {
22
+ return merge;
23
+ },
24
+ createInterval: function() {
25
+ return createInterval;
23
26
  },
24
27
  createEvent: function() {
25
28
  return createEvent;
@@ -40,36 +43,23 @@ class Dismiss extends FunctionExt {
40
43
  }
41
44
  async after(task) {
42
45
  await task();
43
- this();
46
+ await this();
44
47
  }
45
48
  afterTimes(count) {
46
- return ()=>{
49
+ return async ()=>{
47
50
  if (!--count) {
48
- this();
51
+ await this();
49
52
  }
50
53
  };
51
54
  }
52
55
  }
53
- const eventEmitter = async (listeners, ...args)=>{
54
- return Promise.all(listeners.map((listener)=>listener(...args)));
55
- };
56
+ const eventEmitter = (listeners, event)=>Promise.all(listeners.map((listener)=>listener(event)));
56
57
  class Event extends FunctionExt {
57
- static merge(...events) {
58
- const mergedEvent = new Event();
59
- events.forEach((event)=>event.on(mergedEvent));
60
- return mergedEvent;
61
- }
62
- static interval(interval) {
63
- let counter = 0;
64
- const intervalEvent = new Event(()=>clearInterval(timerId));
65
- const timerId = setInterval(()=>intervalEvent(counter++), interval);
66
- return intervalEvent;
67
- }
68
58
  listeners;
69
59
  dispose;
70
60
  constructor(dispose){
71
61
  const listeners = [];
72
- const fn = (...args)=>eventEmitter(listeners, ...args);
62
+ const fn = (event)=>eventEmitter(listeners, event);
73
63
  super(fn);
74
64
  this.listeners = listeners;
75
65
  this.dispose = ()=>{
@@ -98,42 +88,42 @@ class Event extends FunctionExt {
98
88
  return new Dismiss(()=>this.off(listener));
99
89
  }
100
90
  once(listener) {
101
- const oneTimeListener = (...args)=>{
91
+ const oneTimeListener = (event)=>{
102
92
  this.off(oneTimeListener);
103
- return listener(...args);
93
+ return listener(event);
104
94
  };
105
95
  return this.on(oneTimeListener);
106
96
  }
107
97
  clear() {
108
98
  this.listeners.splice(0);
109
99
  }
110
- toPromise() {
111
- return new Promise((resolve)=>this.once((...args)=>resolve(args)));
100
+ onceAsync() {
101
+ return new Promise((resolve)=>this.once((event)=>resolve(event)));
112
102
  }
113
103
  filter(filter) {
114
- const dispose = this.on(async (...args)=>{
115
- if (filteredEvent.size > 0 && await filter(...args)) {
116
- await filteredEvent(...args);
104
+ const dispose = this.on(async (event)=>{
105
+ if (filteredEvent.size > 0 && await filter(event)) {
106
+ await filteredEvent(event);
117
107
  }
118
108
  });
119
109
  const filteredEvent = new Event(dispose);
120
110
  return filteredEvent;
121
111
  }
122
112
  first(filter) {
123
- const dispose = this.on(async (...args)=>{
124
- if (filteredEvent.size > 0 && await filter(...args)) {
125
- dispose();
126
- await filteredEvent(...args);
113
+ const dispose = this.on(async (event)=>{
114
+ if (filteredEvent.size > 0 && await filter(event)) {
115
+ await dispose();
116
+ await filteredEvent(event);
127
117
  }
128
118
  });
129
119
  const filteredEvent = new Event(dispose);
130
120
  return filteredEvent;
131
121
  }
132
122
  map(mapper) {
133
- const dispose = this.on(async (...args)=>{
123
+ const dispose = this.on(async (event)=>{
134
124
  if (mappedEvent.size > 0) {
135
- const value = await mapper(...args);
136
- mappedEvent(value);
125
+ const value = await mapper(event);
126
+ await mappedEvent(value);
137
127
  }
138
128
  });
139
129
  const mappedEvent = new Event(dispose);
@@ -141,10 +131,10 @@ class Event extends FunctionExt {
141
131
  }
142
132
  reduce(reducer, init) {
143
133
  let value = init;
144
- const dispose = this.on(async (...args)=>{
134
+ const dispose = this.on(async (event)=>{
145
135
  if (reducedEvent.size > 0) {
146
- value = await reducer(value, ...args);
147
- reducedEvent(value);
136
+ value = await reducer(value, event);
137
+ await reducedEvent(value);
148
138
  }
149
139
  });
150
140
  const reducedEvent = new Event(dispose);
@@ -152,20 +142,26 @@ class Event extends FunctionExt {
152
142
  }
153
143
  debounce(interval) {
154
144
  let timer;
155
- const dispose = this.on((...args)=>{
145
+ const dispose = this.on((event)=>{
156
146
  clearTimeout(timer);
157
- timer = setTimeout(()=>debouncedEvent(...args), interval);
147
+ timer = setTimeout(()=>debouncedEvent(event), interval);
158
148
  });
159
149
  const debouncedEvent = new Event(dispose);
160
150
  return debouncedEvent;
161
151
  }
162
152
  }
163
- const once = (event)=>{
164
- return new Promise((resolve)=>event.once((...args)=>resolve(args)));
153
+ const merge = (...events)=>{
154
+ const mergedEvent = new Event();
155
+ events.forEach((event)=>event.on(mergedEvent));
156
+ return mergedEvent;
165
157
  };
166
- const createEvent = ()=>{
167
- return new Event();
158
+ const createInterval = (interval)=>{
159
+ let counter = 0;
160
+ const intervalEvent = new Event(()=>clearInterval(timerId));
161
+ const timerId = setInterval(()=>intervalEvent(counter++), interval);
162
+ return intervalEvent;
168
163
  };
164
+ const createEvent = ()=>new Event();
169
165
  const _default = createEvent;
170
166
 
171
167
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export type MaybePromise<T> = Promise<T> | PromiseLike<T> | T;\n\nexport interface Unsubscribe {\n (): void;\n}\n\nexport interface Listener<T extends unknown[], R = unknown> {\n (...args: T): MaybePromise<R | void>;\n}\n\nexport interface Dispose {\n (): void;\n}\n\nexport interface Filter<T extends unknown[]> {\n (...args: T): MaybePromise<boolean>;\n}\n\nexport interface Mapper<T extends unknown[], R> {\n (...args: T): MaybePromise<R>;\n}\n\nexport interface Reducer<T extends unknown[], R> {\n (value: R, ...args: T): MaybePromise<R>;\n}\n\nexport type Listeners<T extends unknown[], R> = Listener<T, R>[];\n\n/**\n * An abstract class that extends the built-in Function class. It allows instances of the class\n * to be called as functions. When an instance of FunctionExt is called as a function, it will\n * call the function passed to its constructor with the same arguments.\n * @internal\n */\nexport abstract class FunctionExt extends Function {\n constructor(func: Function) {\n super();\n return Object.setPrototypeOf(func, new.target.prototype);\n }\n}\n\nexport interface Dismiss {\n (): Promise<void> | void;\n}\n\nexport interface Task {\n (): MaybePromise<unknown>;\n}\n\n/**\n * @internal\n */\nexport class Dismiss extends FunctionExt {\n constructor(callback: Unsubscribe) {\n super(callback);\n }\n\n async after(task: Task): Promise<void> {\n await task();\n this();\n }\n\n afterTimes(count: number): () => void {\n return () => {\n if (!--count) {\n this();\n }\n };\n }\n}\n\nconst eventEmitter = async <A extends unknown[], R>(listeners: Listeners<A, R>, ...args: A) => {\n return Promise.all(listeners.map((listener) => listener(...args)));\n};\n\nexport interface Event<T extends unknown[], R> {\n (...args: T): Promise<(R | undefined)[]>;\n}\n\nexport type EventParameters<T> = T extends Event<infer P, unknown> ? P : never;\n\nexport type EventResult<T> = T extends Event<unknown[], infer R> ? R : never;\n\nexport type AllEventsParameters<T extends Event<unknown[], unknown>[]> = { [K in keyof T]: EventParameters<T[K]> }[number];\n\nexport type AllEventsResults<T extends Event<unknown[], unknown>[]> = { [K in keyof T]: EventResult<T[K]> }[number];\n\n/**\n * A class representing an anonymous event that can be listened to or triggered.\n *\n * @typeParam T - The tuple of arguments that the event takes.\n * @typeParam R - The return type of the event.\n */\nexport class Event<T extends unknown[], R = void> extends FunctionExt {\n /**\n * Merges multiple events into a single event.\n * @example\n * const inputEvent = Event.merge(mouseEvent, keyboardEvent);\n *\n * @param events - The events to merge.\n * @returns The merged event.\n */\n static merge<Events extends Event<any[], any>[]>(...events: Events): Event<AllEventsParameters<Events>, AllEventsResults<Events>> {\n const mergedEvent = new Event<AllEventsParameters<Events>, AllEventsResults<Events>>();\n events.forEach((event) => event.on(mergedEvent));\n return mergedEvent;\n }\n\n /**\n * Creates an event that triggers at a specified interval.\n * @example\n * const tickEvent = Event.interval(1000);\n * tickEvent.on((tickNumber) => console.log(tickNumber));\n *\n * @param interval - The interval at which to trigger the event.\n * @returns The interval event.\n */\n static interval(interval: number): Event<[number], void> {\n let counter = 0;\n const intervalEvent = new Event<[number], void>(() => clearInterval(timerId));\n const timerId: ReturnType<typeof setInterval> = setInterval(() => intervalEvent(counter++), interval);\n return intervalEvent;\n }\n\n /**\n * The array of listeners for the event.\n */\n private listeners: Listeners<T, R>;\n\n /**\n * A function that disposes of the event and its listeners.\n */\n readonly dispose: Dispose;\n\n /**\n * Creates a new event.\n * @example\n * // Create a click event.\n * const clickEvent = new Event<[x: number, y: number], void>();\n * clickEvent.on((x, y) => console.log(`Clicked at ${x}, ${y}`));\n *\n * @param dispose - A function to call on the event disposal.\n */\n constructor(dispose?: Dispose) {\n const listeners: Listeners<T, R> = [];\n const fn = (...args: T) => eventEmitter(listeners, ...args);\n\n super(fn);\n this.listeners = listeners;\n this.dispose = () => {\n this.clear();\n dispose?.();\n };\n }\n\n /**\n * The number of listeners for the event.\n */\n get size(): number {\n return this.listeners.length;\n }\n\n /**\n * Checks if a listener is not registered for the event.\n * @param listener - The listener to check.\n * @returns `true` if the listener is not registered, `false` otherwise.\n */\n lacks(listener: Listener<T, R>): boolean {\n return this.listeners.indexOf(listener) === -1;\n }\n\n /**\n * Checks if a listener is registered for the event.\n * @param listener - The listener to check.\n * @returns `true` if the listener is registered, `false` otherwise.\n */\n has(listener: Listener<T, R>): boolean {\n return this.listeners.indexOf(listener) !== -1;\n }\n\n /**\n * Removes a listener from the event.\n * @param listener - The listener to remove.\n */\n off(listener: Listener<T, R>): void {\n let index = this.listeners.indexOf(listener);\n while (~index) {\n this.listeners.splice(index, 1);\n index = this.listeners.indexOf(listener);\n }\n }\n\n /**\n * Adds a listener to the event.\n * @param listener - The listener to add.\n * @returns An object that can be used to remove the listener.\n */\n on(listener: Listener<T, R>): Dismiss {\n this.listeners.push(listener);\n return new Dismiss(() => this.off(listener));\n }\n\n /**\n * Adds a listener to the event that will only be called once.\n * @param listener - The listener to add.\n * @returns An object that can be used to remove the listener.\n */\n once(listener: Listener<T, R>): Dismiss {\n const oneTimeListener = (...args: T) => {\n this.off(oneTimeListener);\n return listener(...args);\n };\n return this.on(oneTimeListener);\n }\n\n /**\n * Removes all listeners from the event.\n */\n clear(): void {\n this.listeners.splice(0);\n }\n\n /**\n * Returns a Promise that resolves with the first emitted by the event arguments.\n * @returns A Promise that resolves with the first emitted by the event.\n */\n toPromise(): Promise<T> {\n return new Promise((resolve) => this.once((...args) => resolve(args)));\n }\n\n /**\n * Returns a new event that only triggers when the provided filter function returns `true`.\n * @example\n * const spacePressEvent = keyboardEvent.filter((key) => key === 'Space');\n *\n * @param filter The filter function to apply to the event.\n * @returns A new event that only triggers when the provided filter function returns `true`.\n */\n filter<F extends T>(filter: Filter<T>): Event<F, R> {\n const dispose = this.on(async (...args: T) => {\n if (filteredEvent.size > 0 && (await filter(...args))) {\n await filteredEvent(...(args as F));\n }\n });\n const filteredEvent = new Event<F, R>(dispose);\n return filteredEvent;\n }\n\n /**\n * Returns a new event that will only be triggered once the provided filter function returns `true`.\n * @example\n * const escPressEvent = keyboardEvent.first((key) => key === 'Esc');\n * await escPressEvent.toPromise();\n *\n * @param filter - The filter function.\n * @returns A new event that will only be triggered once the provided filter function returns `true`.\n */\n first<F extends T>(filter: Filter<T>): Event<F, R> {\n const dispose = this.on(async (...args: T) => {\n if (filteredEvent.size > 0 && (await filter(...args))) {\n dispose();\n await filteredEvent(...(args as F));\n }\n });\n const filteredEvent = new Event<F, R>(dispose);\n return filteredEvent;\n }\n\n /**\n * Returns a new event that maps the values of this event using the provided mapper function.\n * @example\n * const keyPressEvent = keyboardEvent.map((key) => key.toUpperCase()); // ['a'] -> ['A']\n *\n * @param mapper A function that maps the values of this event to a new value.\n * @returns A new event that emits the mapped values.\n */\n map<M, MR = unknown>(mapper: Mapper<T, M>): Event<[M], MR> {\n const dispose = this.on(async (...args) => {\n if (mappedEvent.size > 0) {\n const value = await mapper(...args);\n mappedEvent(value);\n }\n });\n const mappedEvent = new Event<[M], MR>(dispose);\n return mappedEvent;\n }\n\n /**\n * Returns a new event that reduces the emitted values using the provided reducer function.\n * @example\n * const sumEvent = numberEvent.reduce((a, b) => a + b, 0);\n * sumEvent.on((sum) => console.log(sum)); // 1, 3, 6\n * sumEvent(1);\n * sumEvent(2);\n * sumEvent(3);\n *\n * @typeParam A The type of the accumulated value.\n * @typeParam AR The type of the reduced value.\n * @param {Reducer<T, A>} reducer The reducer function that accumulates the values emitted by this `Event`.\n * @param {A} init The initial value of the accumulated value.\n * @returns {Event<[A], AR>} A new `Event` that emits the reduced value.\n */\n reduce<A, AR = unknown>(reducer: Reducer<T, A>, init: A): Event<[A], AR> {\n let value = init;\n const dispose = this.on(async (...args) => {\n if (reducedEvent.size > 0) {\n value = await reducer(value, ...args);\n reducedEvent(value);\n }\n });\n const reducedEvent = new Event<[A], AR>(dispose);\n return reducedEvent;\n }\n\n /**\n * Returns a new debounced event that will not fire until a certain amount of time has passed\n * since the last time it was triggered.\n * @example\n * const debouncedEvent = textInputEvent.debounce(100);\n * debouncedEvent.on((str) => console.log(str)); // 'test'\n * event('t');\n * event('te');\n * event('tes');\n * event('test');\n *\n * @param interval - The amount of time to wait before firing the debounced event, in milliseconds.\n * @returns A new debounced event.\n */\n debounce(interval: number): Event<T, R> {\n let timer: ReturnType<typeof setTimeout>;\n const dispose = this.on((...args) => {\n clearTimeout(timer);\n timer = setTimeout(() => debouncedEvent(...args), interval);\n });\n const debouncedEvent = new Event<T, R>(dispose);\n return debouncedEvent;\n }\n}\n\n/**\n * Returns a promise that resolves with the arguments passed to the first invocation of the given event.\n * @example\n * const [x, y] = await once(mouseEvent);\n *\n * @param event The event to listen for.\n * @returns A promise that resolves with the arguments passed to the first invocation of the given event.\n */\nexport const once = <T extends unknown[], R = void>(event: Event<T, R>): Promise<T> => {\n return new Promise((resolve) => event.once((...args) => resolve(args)));\n};\n\n/**\n * Creates a new event instance.\n *\n * @typeParam T - An array of argument types that the event will accept.\n * @typeParam R - The return type of the event handler function.\n * @returns A new instance of the `Event` class.\n *\n * @example\n * const myEvent = createEvent<[string], number>();\n * myEvent.on((str: string) => str.length);\n * await myEvent('hello'); // [5]\n */\nexport const createEvent = <T extends unknown[], R = void>(): Event<T, R> => {\n return new Event<T, R>();\n};\n\nexport default createEvent;\n\n/**\n * A type helper that extracts the event listener type\n *\n * @typeParam E - The event type.\n */\nexport type EventHandler<E> = E extends Event<infer T, infer R> ? Listener<T, R> : never;\n\n/**\n * A type helper that extracts the event filter type\n *\n * @typeParam E The event type to filter.\n */\nexport type EventFilter<E> = Filter<EventParameters<E>>;\n\n/**\n * A type helper that extracts the event mapper type\n *\n * @typeParam E The event type to map.\n * @typeParam M The new type to map `E` to.\n */\nexport type EventMapper<E, M> = Mapper<EventParameters<E>, M>;\n\n/**\n * A type helper that extracts the event mapper type\n *\n * @typeParam E The type of event to reduce.\n * @typeParam M The type of reduced event.\n */\nexport type EventReducer<E, R> = Reducer<EventParameters<E>, R>;\n"],"names":["FunctionExt","Dismiss","Event","once","createEvent","Function","constructor","func","Object","setPrototypeOf","prototype","callback","after","task","afterTimes","count","eventEmitter","listeners","args","Promise","all","map","listener","merge","events","mergedEvent","forEach","event","on","interval","counter","intervalEvent","clearInterval","timerId","setInterval","dispose","fn","clear","size","length","lacks","indexOf","has","off","index","splice","push","oneTimeListener","toPromise","resolve","filter","filteredEvent","first","mapper","mappedEvent","value","reduce","reducer","init","reducedEvent","debounce","timer","clearTimeout","setTimeout","debouncedEvent"],"mappings":"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"}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export type MaybePromise<T> = Promise<T> | PromiseLike<T> | T;\n\nexport interface Unsubscribe {\n (): void;\n}\n\nexport interface Listener<T, R = unknown> {\n (event: T): MaybePromise<R | void>;\n}\n\nexport interface Dispose {\n (): void;\n}\n\nexport interface Result<T, E> {\n ok: boolean;\n result: T | E;\n}\n\nexport interface Resolver<T, P> {\n (event: T): Promise<P>;\n}\n\nexport interface FilterFunction<T> {\n (event: T): MaybePromise<boolean>;\n}\n\nexport interface Predicate<T, P extends T> {\n (event: T): event is P;\n}\n\nexport type Filter<T, P extends T> = Predicate<T, P> | FilterFunction<T>;\n\nexport interface Mapper<T, R> {\n (event: T): MaybePromise<R>;\n}\n\nexport interface Reducer<T, R> {\n (result: R, event: T): MaybePromise<R>;\n}\n\nexport type Listeners<T, R> = Listener<T, R>[];\n\n/**\n * An abstract class that extends the built-in Function class. It allows instances of the class\n * to be called as functions. When an instance of FunctionExt is called as a function, it will\n * call the function passed to its constructor with the same arguments.\n * @internal\n */\nexport abstract class FunctionExt extends Function {\n constructor(func: Function) {\n super();\n return Object.setPrototypeOf(func, new.target.prototype);\n }\n}\n\nexport interface Dismiss {\n (): Promise<void> | void;\n}\n\nexport interface Task {\n (): MaybePromise<unknown>;\n}\n\n/**\n * @internal\n */\nexport class Dismiss extends FunctionExt {\n constructor(callback: Unsubscribe) {\n super(callback);\n }\n\n async after(task: Task): Promise<void> {\n await task();\n await this();\n }\n\n afterTimes(count: number): () => Promise<void> {\n return async () => {\n if (!--count) {\n await this();\n }\n };\n }\n}\n\nconst eventEmitter = <A, R>(listeners: Listeners<A, R>, event: A): Promise<(void | R)[]> => Promise.all(listeners.map((listener) => listener(event)));\n\ntype EventType<T> = T extends undefined ? void : T;\n\nexport interface Event<T = unknown, R = void> {\n (event?: EventType<T>): Promise<(R | undefined)[]>;\n}\n\nexport type EventParameters<T> = T extends Event<infer P, unknown> ? P : never;\n\nexport type EventResult<T> = T extends Event<unknown, infer R> ? R : never;\n\nexport type AllEventsParameters<T extends Event<unknown, unknown>[]> = { [K in keyof T]: EventParameters<T[K]> }[number];\n\nexport type AllEventsResults<T extends Event<unknown, unknown>[]> = { [K in keyof T]: EventResult<T[K]> }[number];\n\n/**\n * A class representing an anonymous event that can be listened to or triggered.\n *\n * @typeParam T - The tuple of arguments that the event takes.\n * @typeParam R - The return type of the event.\n */\nexport class Event<T, R> extends FunctionExt {\n /**\n * The array of listeners for the event.\n */\n private listeners: Listeners<T, R>;\n\n /**\n * A function that disposes of the event and its listeners.\n */\n readonly dispose: Dispose;\n\n /**\n * Creates a new event.\n * @example\n * // Create a click event.\n * const clickEvent = new Event<[x: number, y: number], void>();\n * clickEvent.on((x, y) => console.log(`Clicked at ${x}, ${y}`));\n *\n * @param dispose - A function to call on the event disposal.\n */\n constructor(dispose?: Dispose) {\n const listeners: Listeners<T, R> = [];\n const fn = (event: T) => eventEmitter(listeners, event);\n\n super(fn);\n this.listeners = listeners;\n this.dispose = () => {\n this.clear();\n dispose?.();\n };\n }\n\n /**\n * The number of listeners for the event.\n */\n get size(): number {\n return this.listeners.length;\n }\n\n /**\n * Checks if a listener is not registered for the event.\n * @param listener - The listener to check.\n * @returns `true` if the listener is not registered, `false` otherwise.\n */\n lacks(listener: Listener<T, R>): boolean {\n return this.listeners.indexOf(listener) === -1;\n }\n\n /**\n * Checks if a listener is registered for the event.\n * @param listener - The listener to check.\n * @returns `true` if the listener is registered, `false` otherwise.\n */\n has(listener: Listener<T, R>): boolean {\n return this.listeners.indexOf(listener) !== -1;\n }\n\n /**\n * Removes a listener from the event.\n * @param listener - The listener to remove.\n */\n off(listener: Listener<T, R>): void {\n let index = this.listeners.indexOf(listener);\n while (~index) {\n this.listeners.splice(index, 1);\n index = this.listeners.indexOf(listener);\n }\n }\n\n /**\n * Adds a listener to the event.\n * @param listener - The listener to add.\n * @returns An object that can be used to remove the listener.\n */\n on(listener: Listener<T, R>): Dismiss {\n this.listeners.push(listener);\n return new Dismiss(() => this.off(listener));\n }\n\n /**\n * Adds a listener to the event that will only be called once.\n * @param listener - The listener to add.\n * @returns An object that can be used to remove the listener.\n */\n once(listener: Listener<T, R>): Dismiss {\n const oneTimeListener = (event: T) => {\n this.off(oneTimeListener);\n return listener(event);\n };\n return this.on(oneTimeListener);\n }\n\n /**\n * Removes all listeners from the event.\n */\n clear(): void {\n this.listeners.splice(0);\n }\n\n /**\n * Returns a Promise that resolves with the first emitted by the event arguments.\n * @returns A Promise that resolves with the first emitted by the event.\n */\n onceAsync(): Promise<T> {\n return new Promise((resolve) => this.once((event) => resolve(event)));\n }\n\n /**\n * Returns a new event that only triggers when the provided filter function returns `true`.\n * @example\n * const spacePressEvent = keyboardEvent.filter((key) => key === 'Space');\n *\n * @param filter The filter function to apply to the event.\n * @returns A new event that only triggers when the provided filter function returns `true`.\n */\n filter<P extends T>(predicate: Predicate<T, P>): Event<P, R>;\n filter<P extends T>(filter: FilterFunction<T>): Event<P, R>;\n filter<P extends T>(filter: Filter<T, P>): Event<P, R> {\n const dispose = this.on(async (event: T) => {\n if (filteredEvent.size > 0 && (await filter(event))) {\n await filteredEvent(event as EventType<P>);\n }\n });\n const filteredEvent = new Event<P, R>(dispose);\n return filteredEvent;\n }\n\n /**\n * Returns a new event that will only be triggered once the provided filter function returns `true`.\n * @example\n * const escPressEvent = keyboardEvent.first((key) => key === 'Esc');\n * await escPressEvent.toPromise();\n *\n * @param filter - The filter function.\n * @returns A new event that will only be triggered once the provided filter function returns `true`.\n */\n first<P extends T>(predicate: Predicate<T, P>): Event<P, R>;\n first<P extends T>(filter: FilterFunction<T>): Event<P, R>;\n first<P extends T>(filter: Filter<T, P>): Event<P, R> {\n const dispose = this.on(async (event: T) => {\n if (filteredEvent.size > 0 && (await filter(event))) {\n await dispose();\n await filteredEvent(event as EventType<P>);\n }\n });\n const filteredEvent = new Event<P, R>(dispose);\n return filteredEvent;\n }\n\n /**\n * Returns a new event that maps the values of this event using the provided mapper function.\n * @example\n * const keyPressEvent = keyboardEvent.map((key) => key.toUpperCase()); // ['a'] -> ['A']\n *\n * @param mapper A function that maps the values of this event to a new value.\n * @returns A new event that emits the mapped values.\n */\n map<M, MR = R>(mapper: Mapper<T, M>): Event<M, MR> {\n const dispose = this.on(async (event) => {\n if (mappedEvent.size > 0) {\n const value = await mapper(event);\n await mappedEvent(value as EventType<M>);\n }\n });\n const mappedEvent = new Event<M, MR>(dispose);\n return mappedEvent;\n }\n\n /**\n * Returns a new event that reduces the emitted values using the provided reducer function.\n * @example\n * const sumEvent = numberEvent.reduce((a, b) => a + b, 0);\n * sumEvent.on((sum) => console.log(sum)); // 1, 3, 6\n * sumEvent(1);\n * sumEvent(2);\n * sumEvent(3);\n *\n * @typeParam A The type of the accumulated value.\n * @typeParam AR The type of the reduced value.\n * @param {Reducer<T, A>} reducer The reducer function that accumulates the values emitted by this `Event`.\n * @param {A} init The initial value of the accumulated value.\n * @returns {Event<[A], AR>} A new `Event` that emits the reduced value.\n */\n reduce<A, AR = R>(reducer: Reducer<T, A>, init: A): Event<A, AR> {\n let value = init;\n const dispose = this.on(async (event) => {\n if (reducedEvent.size > 0) {\n value = await reducer(value, event);\n await reducedEvent(value as EventType<A>);\n }\n });\n const reducedEvent = new Event<A, AR>(dispose);\n return reducedEvent;\n }\n\n /**\n * Returns a new debounced event that will not fire until a certain amount of time has passed\n * since the last time it was triggered.\n * @example\n * const debouncedEvent = textInputEvent.debounce(100);\n * debouncedEvent.on((str) => console.log(str)); // 'test'\n * event('t');\n * event('te');\n * event('tes');\n * event('test');\n *\n * @param interval - The amount of time to wait before firing the debounced event, in milliseconds.\n * @returns A new debounced event.\n */\n debounce(interval: number): Event<T, R> {\n let timer: ReturnType<typeof setTimeout>;\n const dispose = this.on((event) => {\n clearTimeout(timer);\n timer = setTimeout(() => debouncedEvent(event as EventType<T>), interval);\n });\n const debouncedEvent = new Event<T, R>(dispose);\n return debouncedEvent;\n }\n}\n\n/**\n * Merges multiple events into a single event.\n * @example\n * const inputEvent = Event.merge(mouseEvent, keyboardEvent);\n *\n * @param events - The events to merge.\n * @returns The merged event.\n */\nexport const merge = <Events extends Event<any, any>[]>(...events: Events): Event<AllEventsParameters<Events>, AllEventsResults<Events>> => {\n const mergedEvent = new Event<AllEventsParameters<Events>, AllEventsResults<Events>>();\n events.forEach((event) => event.on(mergedEvent));\n return mergedEvent;\n};\n\n/**\n * Creates an event that triggers at a specified interval.\n * @example\n * const tickEvent = Event.interval(1000);\n * tickEvent.on((tickNumber) => console.log(tickNumber));\n *\n * @param interval - The interval at which to trigger the event.\n * @returns The interval event.\n */\nexport const createInterval = <R = void>(interval: number): Event<number, R> => {\n let counter = 0;\n const intervalEvent = new Event<number, R>(() => clearInterval(timerId));\n const timerId: ReturnType<typeof setInterval> = setInterval(() => intervalEvent(counter++), interval);\n return intervalEvent;\n};\n\n/**\n * Creates a new event instance.\n *\n * @typeParam T - An array of argument types that the event will accept.\n * @typeParam R - The return type of the event handler function.\n * @returns A new instance of the `Event` class.\n *\n * @example\n * const myEvent = createEvent<[string], number>();\n * myEvent.on((str: string) => str.length);\n * await myEvent('hello'); // [5]\n */\nexport const createEvent = <T, R = void>(): Event<T, R> => new Event<T, R>();\n\nexport default createEvent;\n\n/**\n * A type helper that extracts the event listener type\n *\n * @typeParam E - The event type.\n */\nexport type EventHandler<E> = E extends Event<infer T, infer R> ? Listener<T, R> : never;\n\n/**\n * A type helper that extracts the event filter type\n *\n * @typeParam E The event type to filter.\n */\nexport type EventFilter<E> = FilterFunction<EventParameters<E>>;\n\n/**\n * A type helper that extracts the event predicate type\n *\n * @typeParam E The event type to predicate.\n */\nexport type EventPredicate<E, P extends EventParameters<E>> = Predicate<EventParameters<E>, P>;\n\n/**\n * A type helper that extracts the event mapper type\n *\n * @typeParam E The event type to map.\n * @typeParam M The new type to map `E` to.\n */\nexport type EventMapper<E, M> = Mapper<EventParameters<E>, M>;\n\n/**\n * A type helper that extracts the event mapper type\n *\n * @typeParam E The type of event to reduce.\n * @typeParam M The type of reduced event.\n */\nexport type EventReducer<E, R> = Reducer<EventParameters<E>, R>;\n"],"names":["FunctionExt","Dismiss","Event","merge","createInterval","createEvent","Function","constructor","func","Object","setPrototypeOf","prototype","callback","after","task","afterTimes","count","eventEmitter","listeners","event","Promise","all","map","listener","dispose","fn","clear","size","length","lacks","indexOf","has","off","index","splice","on","push","once","oneTimeListener","onceAsync","resolve","filter","filteredEvent","first","mapper","mappedEvent","value","reduce","reducer","init","reducedEvent","debounce","interval","timer","clearTimeout","setTimeout","debouncedEvent","events","mergedEvent","forEach","counter","intervalEvent","clearInterval","timerId","setInterval"],"mappings":"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"}
package/build/index.d.ts CHANGED
@@ -2,22 +2,33 @@ export type MaybePromise<T> = Promise<T> | PromiseLike<T> | T;
2
2
  export interface Unsubscribe {
3
3
  (): void;
4
4
  }
5
- export interface Listener<T extends unknown[], R = unknown> {
6
- (...args: T): MaybePromise<R | void>;
5
+ export interface Listener<T, R = unknown> {
6
+ (event: T): MaybePromise<R | void>;
7
7
  }
8
8
  export interface Dispose {
9
9
  (): void;
10
10
  }
11
- export interface Filter<T extends unknown[]> {
12
- (...args: T): MaybePromise<boolean>;
11
+ export interface Result<T, E> {
12
+ ok: boolean;
13
+ result: T | E;
13
14
  }
14
- export interface Mapper<T extends unknown[], R> {
15
- (...args: T): MaybePromise<R>;
15
+ export interface Resolver<T, P> {
16
+ (event: T): Promise<P>;
16
17
  }
17
- export interface Reducer<T extends unknown[], R> {
18
- (value: R, ...args: T): MaybePromise<R>;
18
+ export interface FilterFunction<T> {
19
+ (event: T): MaybePromise<boolean>;
19
20
  }
20
- export type Listeners<T extends unknown[], R> = Listener<T, R>[];
21
+ export interface Predicate<T, P extends T> {
22
+ (event: T): event is P;
23
+ }
24
+ export type Filter<T, P extends T> = Predicate<T, P> | FilterFunction<T>;
25
+ export interface Mapper<T, R> {
26
+ (event: T): MaybePromise<R>;
27
+ }
28
+ export interface Reducer<T, R> {
29
+ (result: R, event: T): MaybePromise<R>;
30
+ }
31
+ export type Listeners<T, R> = Listener<T, R>[];
21
32
  /**
22
33
  * An abstract class that extends the built-in Function class. It allows instances of the class
23
34
  * to be called as functions. When an instance of FunctionExt is called as a function, it will
@@ -39,17 +50,18 @@ export interface Task {
39
50
  export declare class Dismiss extends FunctionExt {
40
51
  constructor(callback: Unsubscribe);
41
52
  after(task: Task): Promise<void>;
42
- afterTimes(count: number): () => void;
53
+ afterTimes(count: number): () => Promise<void>;
43
54
  }
44
- export interface Event<T extends unknown[], R> {
45
- (...args: T): Promise<(R | undefined)[]>;
55
+ type EventType<T> = T extends undefined ? void : T;
56
+ export interface Event<T = unknown, R = void> {
57
+ (event?: EventType<T>): Promise<(R | undefined)[]>;
46
58
  }
47
59
  export type EventParameters<T> = T extends Event<infer P, unknown> ? P : never;
48
- export type EventResult<T> = T extends Event<unknown[], infer R> ? R : never;
49
- export type AllEventsParameters<T extends Event<unknown[], unknown>[]> = {
60
+ export type EventResult<T> = T extends Event<unknown, infer R> ? R : never;
61
+ export type AllEventsParameters<T extends Event<unknown, unknown>[]> = {
50
62
  [K in keyof T]: EventParameters<T[K]>;
51
63
  }[number];
52
- export type AllEventsResults<T extends Event<unknown[], unknown>[]> = {
64
+ export type AllEventsResults<T extends Event<unknown, unknown>[]> = {
53
65
  [K in keyof T]: EventResult<T[K]>;
54
66
  }[number];
55
67
  /**
@@ -58,26 +70,7 @@ export type AllEventsResults<T extends Event<unknown[], unknown>[]> = {
58
70
  * @typeParam T - The tuple of arguments that the event takes.
59
71
  * @typeParam R - The return type of the event.
60
72
  */
61
- export declare class Event<T extends unknown[], R = void> extends FunctionExt {
62
- /**
63
- * Merges multiple events into a single event.
64
- * @example
65
- * const inputEvent = Event.merge(mouseEvent, keyboardEvent);
66
- *
67
- * @param events - The events to merge.
68
- * @returns The merged event.
69
- */
70
- static merge<Events extends Event<any[], any>[]>(...events: Events): Event<AllEventsParameters<Events>, AllEventsResults<Events>>;
71
- /**
72
- * Creates an event that triggers at a specified interval.
73
- * @example
74
- * const tickEvent = Event.interval(1000);
75
- * tickEvent.on((tickNumber) => console.log(tickNumber));
76
- *
77
- * @param interval - The interval at which to trigger the event.
78
- * @returns The interval event.
79
- */
80
- static interval(interval: number): Event<[number], void>;
73
+ export declare class Event<T, R> extends FunctionExt {
81
74
  /**
82
75
  * The array of listeners for the event.
83
76
  */
@@ -137,7 +130,7 @@ export declare class Event<T extends unknown[], R = void> extends FunctionExt {
137
130
  * Returns a Promise that resolves with the first emitted by the event arguments.
138
131
  * @returns A Promise that resolves with the first emitted by the event.
139
132
  */
140
- toPromise(): Promise<T>;
133
+ onceAsync(): Promise<T>;
141
134
  /**
142
135
  * Returns a new event that only triggers when the provided filter function returns `true`.
143
136
  * @example
@@ -146,7 +139,8 @@ export declare class Event<T extends unknown[], R = void> extends FunctionExt {
146
139
  * @param filter The filter function to apply to the event.
147
140
  * @returns A new event that only triggers when the provided filter function returns `true`.
148
141
  */
149
- filter<F extends T>(filter: Filter<T>): Event<F, R>;
142
+ filter<P extends T>(predicate: Predicate<T, P>): Event<P, R>;
143
+ filter<P extends T>(filter: FilterFunction<T>): Event<P, R>;
150
144
  /**
151
145
  * Returns a new event that will only be triggered once the provided filter function returns `true`.
152
146
  * @example
@@ -156,7 +150,8 @@ export declare class Event<T extends unknown[], R = void> extends FunctionExt {
156
150
  * @param filter - The filter function.
157
151
  * @returns A new event that will only be triggered once the provided filter function returns `true`.
158
152
  */
159
- first<F extends T>(filter: Filter<T>): Event<F, R>;
153
+ first<P extends T>(predicate: Predicate<T, P>): Event<P, R>;
154
+ first<P extends T>(filter: FilterFunction<T>): Event<P, R>;
160
155
  /**
161
156
  * Returns a new event that maps the values of this event using the provided mapper function.
162
157
  * @example
@@ -165,7 +160,7 @@ export declare class Event<T extends unknown[], R = void> extends FunctionExt {
165
160
  * @param mapper A function that maps the values of this event to a new value.
166
161
  * @returns A new event that emits the mapped values.
167
162
  */
168
- map<M, MR = unknown>(mapper: Mapper<T, M>): Event<[M], MR>;
163
+ map<M, MR = R>(mapper: Mapper<T, M>): Event<M, MR>;
169
164
  /**
170
165
  * Returns a new event that reduces the emitted values using the provided reducer function.
171
166
  * @example
@@ -181,7 +176,7 @@ export declare class Event<T extends unknown[], R = void> extends FunctionExt {
181
176
  * @param {A} init The initial value of the accumulated value.
182
177
  * @returns {Event<[A], AR>} A new `Event` that emits the reduced value.
183
178
  */
184
- reduce<A, AR = unknown>(reducer: Reducer<T, A>, init: A): Event<[A], AR>;
179
+ reduce<A, AR = R>(reducer: Reducer<T, A>, init: A): Event<A, AR>;
185
180
  /**
186
181
  * Returns a new debounced event that will not fire until a certain amount of time has passed
187
182
  * since the last time it was triggered.
@@ -199,14 +194,24 @@ export declare class Event<T extends unknown[], R = void> extends FunctionExt {
199
194
  debounce(interval: number): Event<T, R>;
200
195
  }
201
196
  /**
202
- * Returns a promise that resolves with the arguments passed to the first invocation of the given event.
197
+ * Merges multiple events into a single event.
203
198
  * @example
204
- * const [x, y] = await once(mouseEvent);
199
+ * const inputEvent = Event.merge(mouseEvent, keyboardEvent);
205
200
  *
206
- * @param event The event to listen for.
207
- * @returns A promise that resolves with the arguments passed to the first invocation of the given event.
201
+ * @param events - The events to merge.
202
+ * @returns The merged event.
208
203
  */
209
- export declare const once: <T extends unknown[], R = void>(event: Event<T, R>) => Promise<T>;
204
+ export declare const merge: <Events extends Event<any, any>[]>(...events: Events) => Event<AllEventsParameters<Events>, AllEventsResults<Events>>;
205
+ /**
206
+ * Creates an event that triggers at a specified interval.
207
+ * @example
208
+ * const tickEvent = Event.interval(1000);
209
+ * tickEvent.on((tickNumber) => console.log(tickNumber));
210
+ *
211
+ * @param interval - The interval at which to trigger the event.
212
+ * @returns The interval event.
213
+ */
214
+ export declare const createInterval: <R = void>(interval: number) => Event<number, R>;
210
215
  /**
211
216
  * Creates a new event instance.
212
217
  *
@@ -219,7 +224,7 @@ export declare const once: <T extends unknown[], R = void>(event: Event<T, R>) =
219
224
  * myEvent.on((str: string) => str.length);
220
225
  * await myEvent('hello'); // [5]
221
226
  */
222
- export declare const createEvent: <T extends unknown[], R = void>() => Event<T, R>;
227
+ export declare const createEvent: <T, R = void>() => Event<T, R>;
223
228
  export default createEvent;
224
229
  /**
225
230
  * A type helper that extracts the event listener type
@@ -232,7 +237,13 @@ export type EventHandler<E> = E extends Event<infer T, infer R> ? Listener<T, R>
232
237
  *
233
238
  * @typeParam E The event type to filter.
234
239
  */
235
- export type EventFilter<E> = Filter<EventParameters<E>>;
240
+ export type EventFilter<E> = FilterFunction<EventParameters<E>>;
241
+ /**
242
+ * A type helper that extracts the event predicate type
243
+ *
244
+ * @typeParam E The event type to predicate.
245
+ */
246
+ export type EventPredicate<E, P extends EventParameters<E>> = Predicate<EventParameters<E>, P>;
236
247
  /**
237
248
  * A type helper that extracts the event mapper type
238
249
  *