index.d.ts 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. /**
  2. Emittery accepts strings and symbols as event names.
  3. Symbol event names can be used to avoid name collisions when your classes are extended, especially for internal events.
  4. */
  5. type EventName = string | symbol;
  6. /**
  7. Emittery also accepts an array of strings and symbols as event names.
  8. */
  9. type EventNames = EventName | readonly EventName[];
  10. declare class Emittery {
  11. /**
  12. In TypeScript, it returns a decorator which mixins `Emittery` as property `emitteryPropertyName` and `methodNames`, or all `Emittery` methods if `methodNames` is not defined, into the target class.
  13. @example
  14. ```
  15. import Emittery = require('emittery');
  16. @Emittery.mixin('emittery')
  17. class MyClass {}
  18. const instance = new MyClass();
  19. instance.emit('event');
  20. ```
  21. */
  22. static mixin(emitteryPropertyName: string | symbol, methodNames?: readonly string[]): Function;
  23. /**
  24. Fires when an event listener was added.
  25. An object with `listener` and `eventName` (if `on` or `off` was used) is provided as event data.
  26. @example
  27. ```
  28. import Emittery = require('emittery');
  29. const emitter = new Emittery();
  30. emitter.on(Emittery.listenerAdded, ({listener, eventName}) => {
  31. console.log(listener);
  32. //=> data => {}
  33. console.log(eventName);
  34. //=> '🦄'
  35. });
  36. emitter.on('🦄', data => {
  37. // Handle data
  38. });
  39. ```
  40. */
  41. static readonly listenerAdded: unique symbol;
  42. /**
  43. Fires when an event listener was removed.
  44. An object with `listener` and `eventName` (if `on` or `off` was used) is provided as event data.
  45. @example
  46. ```
  47. import Emittery = require('emittery');
  48. const emitter = new Emittery();
  49. const off = emitter.on('🦄', data => {
  50. // Handle data
  51. });
  52. emitter.on(Emittery.listenerRemoved, ({listener, eventName}) => {
  53. console.log(listener);
  54. //=> data => {}
  55. console.log(eventName);
  56. //=> '🦄'
  57. });
  58. off();
  59. ```
  60. */
  61. static readonly listenerRemoved: unique symbol;
  62. /**
  63. Subscribe to one or more events.
  64. Using the same listener multiple times for the same event will result in only one method call per emitted event.
  65. @returns An unsubscribe method.
  66. @example
  67. ```
  68. import Emittery = require('emittery');
  69. const emitter = new Emittery();
  70. emitter.on('🦄', data => {
  71. console.log(data);
  72. });
  73. emitter.on(['🦄', '🐶'], data => {
  74. console.log(data);
  75. });
  76. emitter.emit('🦄', '🌈'); // log => '🌈' x2
  77. emitter.emit('🐶', '🍖'); // log => '🍖'
  78. ```
  79. */
  80. on(eventName: typeof Emittery.listenerAdded | typeof Emittery.listenerRemoved, listener: (eventData: Emittery.ListenerChangedData) => void): Emittery.UnsubscribeFn
  81. on(eventName: EventNames, listener: (eventData?: unknown) => void): Emittery.UnsubscribeFn;
  82. /**
  83. Get an async iterator which buffers data each time an event is emitted.
  84. Call `return()` on the iterator to remove the subscription.
  85. @example
  86. ```
  87. import Emittery = require('emittery');
  88. const emitter = new Emittery();
  89. const iterator = emitter.events('🦄');
  90. emitter.emit('🦄', '🌈1'); // Buffered
  91. emitter.emit('🦄', '🌈2'); // Buffered
  92. iterator
  93. .next()
  94. .then(({value, done}) => {
  95. // done === false
  96. // value === '🌈1'
  97. return iterator.next();
  98. })
  99. .then(({value, done}) => {
  100. // done === false
  101. // value === '🌈2'
  102. // Revoke subscription
  103. return iterator.return();
  104. })
  105. .then(({done}) => {
  106. // done === true
  107. });
  108. ```
  109. In practice you would usually consume the events using the [for await](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of) statement. In that case, to revoke the subscription simply break the loop.
  110. @example
  111. ```
  112. import Emittery = require('emittery');
  113. const emitter = new Emittery();
  114. const iterator = emitter.events('🦄');
  115. emitter.emit('🦄', '🌈1'); // Buffered
  116. emitter.emit('🦄', '🌈2'); // Buffered
  117. // In an async context.
  118. for await (const data of iterator) {
  119. if (data === '🌈2') {
  120. break; // Revoke the subscription when we see the value `🌈2`.
  121. }
  122. }
  123. ```
  124. It accepts multiple event names.
  125. @example
  126. ```
  127. import Emittery = require('emittery');
  128. const emitter = new Emittery();
  129. const iterator = emitter.events(['🦄', '🦊']);
  130. emitter.emit('🦄', '🌈1'); // Buffered
  131. emitter.emit('🦊', '🌈2'); // Buffered
  132. iterator
  133. .next()
  134. .then(({value, done}) => {
  135. // done === false
  136. // value === '🌈1'
  137. return iterator.next();
  138. })
  139. .then(({value, done}) => {
  140. // done === false
  141. // value === '🌈2'
  142. // Revoke subscription
  143. return iterator.return();
  144. })
  145. .then(({done}) => {
  146. // done === true
  147. });
  148. ```
  149. */
  150. events(eventName: EventNames): AsyncIterableIterator<unknown>
  151. /**
  152. Remove one or more event subscriptions.
  153. @example
  154. ```
  155. import Emittery = require('emittery');
  156. const emitter = new Emittery();
  157. const listener = data => console.log(data);
  158. (async () => {
  159. emitter.on(['🦄', '🐶', '🦊'], listener);
  160. await emitter.emit('🦄', 'a');
  161. await emitter.emit('🐶', 'b');
  162. await emitter.emit('🦊', 'c');
  163. emitter.off('🦄', listener);
  164. emitter.off(['🐶', '🦊'], listener);
  165. await emitter.emit('🦄', 'a'); // nothing happens
  166. await emitter.emit('🐶', 'b'); // nothing happens
  167. await emitter.emit('🦊', 'c'); // nothing happens
  168. })();
  169. ```
  170. */
  171. off(eventName: EventNames, listener: (eventData?: unknown) => void): void;
  172. /**
  173. Subscribe to one or more events only once. It will be unsubscribed after the first
  174. event.
  175. @returns The event data when `eventName` is emitted.
  176. @example
  177. ```
  178. import Emittery = require('emittery');
  179. const emitter = new Emittery();
  180. emitter.once('🦄').then(data => {
  181. console.log(data);
  182. //=> '🌈'
  183. });
  184. emitter.once(['🦄', '🐶']).then(data => {
  185. console.log(data);
  186. });
  187. emitter.emit('🦄', '🌈'); // Logs `🌈` twice
  188. emitter.emit('🐶', '🍖'); // Nothing happens
  189. ```
  190. */
  191. once(eventName: typeof Emittery.listenerAdded | typeof Emittery.listenerRemoved): Promise<Emittery.ListenerChangedData>
  192. once(eventName: EventNames): Promise<unknown>;
  193. /**
  194. Trigger an event asynchronously, optionally with some data. Listeners are called in the order they were added, but executed concurrently.
  195. @returns A promise that resolves when all the event listeners are done. *Done* meaning executed if synchronous or resolved when an async/promise-returning function. You usually wouldn't want to wait for this, but you could for example catch possible errors. If any of the listeners throw/reject, the returned promise will be rejected with the error, but the other listeners will not be affected.
  196. */
  197. emit(eventName: EventName, eventData?: unknown): Promise<void>;
  198. /**
  199. Same as `emit()`, but it waits for each listener to resolve before triggering the next one. This can be useful if your events depend on each other. Although ideally they should not. Prefer `emit()` whenever possible.
  200. If any of the listeners throw/reject, the returned promise will be rejected with the error and the remaining listeners will *not* be called.
  201. @returns A promise that resolves when all the event listeners are done.
  202. */
  203. emitSerial(eventName: EventName, eventData?: unknown): Promise<void>;
  204. /**
  205. Subscribe to be notified about any event.
  206. @returns A method to unsubscribe.
  207. */
  208. onAny(listener: (eventName: EventName, eventData?: unknown) => unknown): Emittery.UnsubscribeFn;
  209. /**
  210. Get an async iterator which buffers a tuple of an event name and data each time an event is emitted.
  211. Call `return()` on the iterator to remove the subscription.
  212. In the same way as for `events`, you can subscribe by using the `for await` statement.
  213. @example
  214. ```
  215. import Emittery = require('emittery');
  216. const emitter = new Emittery();
  217. const iterator = emitter.anyEvent();
  218. emitter.emit('🦄', '🌈1'); // Buffered
  219. emitter.emit('🌟', '🌈2'); // Buffered
  220. iterator.next()
  221. .then(({value, done}) => {
  222. // done is false
  223. // value is ['🦄', '🌈1']
  224. return iterator.next();
  225. })
  226. .then(({value, done}) => {
  227. // done is false
  228. // value is ['🌟', '🌈2']
  229. // revoke subscription
  230. return iterator.return();
  231. })
  232. .then(({done}) => {
  233. // done is true
  234. });
  235. ```
  236. */
  237. anyEvent(): AsyncIterableIterator<unknown>
  238. /**
  239. Remove an `onAny` subscription.
  240. */
  241. offAny(listener: (eventName: EventName, eventData?: unknown) => void): void;
  242. /**
  243. Clear all event listeners on the instance.
  244. If `eventName` is given, only the listeners for that event are cleared.
  245. */
  246. clearListeners(eventName?: EventNames): void;
  247. /**
  248. The number of listeners for the `eventName` or all events if not specified.
  249. */
  250. listenerCount(eventName?: EventNames): number;
  251. /**
  252. Bind the given `methodNames`, or all `Emittery` methods if `methodNames` is not defined, into the `target` object.
  253. @example
  254. ```
  255. import Emittery = require('emittery');
  256. const object = {};
  257. new Emittery().bindMethods(object);
  258. object.emit('event');
  259. ```
  260. */
  261. bindMethods(target: object, methodNames?: readonly string[]): void;
  262. }
  263. declare namespace Emittery {
  264. /**
  265. Removes an event subscription.
  266. */
  267. type UnsubscribeFn = () => void;
  268. type EventNameFromDataMap<EventDataMap> = Extract<keyof EventDataMap, EventName>;
  269. /**
  270. Maps event names to their emitted data type.
  271. */
  272. interface Events {
  273. // Blocked by https://github.com/microsoft/TypeScript/issues/1863, should be
  274. // `[eventName: EventName]: unknown;`
  275. }
  276. /**
  277. The data provided as `eventData` when listening for `Emittery.listenerAdded` or `Emittery.listenerRemoved`.
  278. */
  279. interface ListenerChangedData {
  280. /**
  281. The listener that was added or removed.
  282. */
  283. listener: (eventData?: unknown) => void;
  284. /**
  285. The name of the event that was added or removed if `.on()` or `.off()` was used, or `undefined` if `.onAny()` or `.offAny()` was used.
  286. */
  287. eventName?: EventName;
  288. }
  289. /**
  290. Async event emitter.
  291. You must list supported events and the data type they emit, if any.
  292. @example
  293. ```
  294. import Emittery = require('emittery');
  295. const emitter = new Emittery.Typed<{value: string}, 'open' | 'close'>();
  296. emitter.emit('open');
  297. emitter.emit('value', 'foo\n');
  298. emitter.emit('value', 1); // TS compilation error
  299. emitter.emit('end'); // TS compilation error
  300. ```
  301. */
  302. class Typed<EventDataMap extends Events, EmptyEvents extends EventName = never> extends Emittery {
  303. on<Name extends EventNameFromDataMap<EventDataMap>>(eventName: Name, listener: (eventData: EventDataMap[Name]) => void): Emittery.UnsubscribeFn;
  304. on<Name extends EmptyEvents>(eventName: Name, listener: () => void): Emittery.UnsubscribeFn;
  305. events<Name extends EventNameFromDataMap<EventDataMap>>(eventName: Name): AsyncIterableIterator<EventDataMap[Name]>;
  306. once<Name extends EventNameFromDataMap<EventDataMap>>(eventName: Name): Promise<EventDataMap[Name]>;
  307. once<Name extends EmptyEvents>(eventName: Name): Promise<void>;
  308. off<Name extends EventNameFromDataMap<EventDataMap>>(eventName: Name, listener: (eventData: EventDataMap[Name]) => void): void;
  309. off<Name extends EmptyEvents>(eventName: Name, listener: () => void): void;
  310. onAny(listener: (eventName: EventNameFromDataMap<EventDataMap> | EmptyEvents, eventData?: EventDataMap[EventNameFromDataMap<EventDataMap>]) => void): Emittery.UnsubscribeFn;
  311. anyEvent(): AsyncIterableIterator<[EventNameFromDataMap<EventDataMap>, EventDataMap[EventNameFromDataMap<EventDataMap>]]>;
  312. offAny(listener: (eventName: EventNameFromDataMap<EventDataMap> | EmptyEvents, eventData?: EventDataMap[EventNameFromDataMap<EventDataMap>]) => void): void;
  313. emit<Name extends EventNameFromDataMap<EventDataMap>>(eventName: Name, eventData: EventDataMap[Name]): Promise<void>;
  314. emit<Name extends EmptyEvents>(eventName: Name): Promise<void>;
  315. emitSerial<Name extends EventNameFromDataMap<EventDataMap>>(eventName: Name, eventData: EventDataMap[Name]): Promise<void>;
  316. emitSerial<Name extends EmptyEvents>(eventName: Name): Promise<void>;
  317. }
  318. }
  319. export = Emittery;