Skip to content

Commit 5116df4

Browse files
Add generic types and update tests (#107)
* Add generic types and update tests * Add generic types to `on`, `off` and `emit` to enable some nicer TS usage if you specify what type you're expecting from the `EventData`. * Move the tests to be TypeScript source. This will help catch errors in the tests if there are any type errors. * Create a new test to test the generic types and make sure they pass and error when expected. * Upgrade to Mocha 8. * Did some tidying up of the package.json scripts. * Tweak TS setup to validate tests * Fix d.ts generation and tests Co-authored-by: Jason Miller <[email protected]>
1 parent 244cac2 commit 5116df4

File tree

9 files changed

+86
-44
lines changed

9 files changed

+86
-44
lines changed

.editorconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ insert_final_newline = true
1010
[{package.json,.*rc,*.yml}]
1111
indent_style = space
1212
indent_size = 2
13+
insert_final_newline = false
1314

1415
[*.md]
1516
trim_trailing_whitespace = false

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
/test-reports
33
/node_modules
44
/npm-debug.log
5+
/index.d.ts
56
package-lock.json
67
.DS_Store
78
.idea

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ const emitter: mitt.Emitter = mitt();
110110

111111
Mitt: Tiny (~200b) functional event emitter / pubsub.
112112

113-
Returns **Mitt**
113+
Returns **Mitt**
114114

115115
### on
116116

package.json

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@
88
"esmodules": "dist/mitt.modern.js",
99
"main": "dist/mitt.js",
1010
"umd:main": "dist/mitt.umd.js",
11-
"typings": "dist/index.d.ts",
11+
"typings": "index.d.ts",
1212
"scripts": {
13-
"test": "npm-run-all --silent typecheck lint testonly",
14-
"testonly": "mocha --require esm test/**/*.js",
13+
"test": "npm-run-all --silent typecheck lint mocha test-types",
14+
"mocha": "mocha test",
15+
"test-types": "tsc test/test-types-compilation.ts --noEmit",
1516
"lint": "eslint src test --ext ts --ext js",
16-
"typecheck": "tsc **/*.ts --noEmit",
17+
"typecheck": "tsc --noEmit",
1718
"bundle": "microbundle",
1819
"build": "npm-run-all --silent clean -p bundle -s docs",
1920
"clean": "rimraf dist",
@@ -34,8 +35,21 @@
3435
"license": "MIT",
3536
"files": [
3637
"src",
37-
"dist"
38+
"dist",
39+
"index.d.ts"
3840
],
41+
"mocha": {
42+
"extension": [
43+
"ts"
44+
],
45+
"require": [
46+
"ts-node/register",
47+
"esm"
48+
],
49+
"spec": [
50+
"test/*_test.ts"
51+
]
52+
},
3953
"eslintConfig": {
4054
"extends": [
4155
"developit",
@@ -68,7 +82,8 @@
6882
}
6983
},
7084
"eslintIgnore": [
71-
"dist"
85+
"dist",
86+
"index.d.ts"
7287
],
7388
"devDependencies": {
7489
"@types/chai": "^4.2.11",
@@ -82,13 +97,13 @@
8297
"eslint": "^7.1.0",
8398
"eslint-config-developit": "^1.2.0",
8499
"esm": "^3.2.25",
85-
"microbundle": "^0.12.0",
86-
"mocha": "^7.2.0",
100+
"microbundle": "^0.12.3",
101+
"mocha": "^8.0.1",
87102
"npm-run-all": "^4.1.5",
88103
"rimraf": "^3.0.2",
89104
"sinon": "^9.0.2",
90105
"sinon-chai": "^3.5.0",
91-
"ts-node": "^8.10.1",
106+
"ts-node": "^8.10.2",
92107
"typescript": "^3.9.3"
93108
}
94-
}
109+
}

src/index.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ export type EventType = string | symbol;
22

33
// An event handler can take an optional event argument
44
// and should not return a value
5-
export type Handler = (event?: any) => void;
6-
export type WildcardHandler = (type: EventType, event?: any) => void
5+
export type Handler<T = any> = (event?: T) => void;
6+
export type WildcardHandler = (type: EventType, event?: any) => void;
77

88
// An array of all currently registered event handlers for a type
99
export type EventHandlerList = Array<Handler>;
@@ -13,10 +13,10 @@ export type WildCardEventHandlerList = Array<WildcardHandler>;
1313
export type EventHandlerMap = Map<EventType, EventHandlerList | WildCardEventHandlerList>;
1414

1515
export interface Emitter {
16-
on(type: EventType, handler: Handler): void;
16+
on<T = any>(type: EventType, handler: Handler<T>): void;
1717
on(type: '*', handler: WildcardHandler): void;
1818

19-
off(type: EventType, handler: Handler): void;
19+
off<T = any>(type: EventType, handler: Handler<T>): void;
2020
off(type: '*', handler: WildcardHandler): void;
2121

2222
emit<T = any>(type: EventType, event?: T): void;
@@ -38,7 +38,7 @@ export default function mitt(all?: EventHandlerMap): Emitter {
3838
* @param {Function} handler Function to call in response to given event
3939
* @memberOf mitt
4040
*/
41-
on(type: EventType, handler: Handler) {
41+
on<T = any>(type: EventType, handler: Handler<T>) {
4242
const handlers = all.get(type);
4343
const added = handlers && handlers.push(handler);
4444
if (!added) {
@@ -53,7 +53,7 @@ export default function mitt(all?: EventHandlerMap): Emitter {
5353
* @param {Function} handler Handler function to remove
5454
* @memberOf mitt
5555
*/
56-
off(type: EventType, handler: Handler) {
56+
off<T = any>(type: EventType, handler: Handler<T>) {
5757
const handlers = all.get(type);
5858
if (handlers) {
5959
handlers.splice(handlers.indexOf(handler) >>> 0, 1);
@@ -70,7 +70,7 @@ export default function mitt(all?: EventHandlerMap): Emitter {
7070
* @param {Any} [evt] Any value (object is recommended and powerful), passed to each handler
7171
* @memberOf mitt
7272
*/
73-
emit(type: EventType, evt: any) {
73+
emit<T = any>(type: EventType, evt: T) {
7474
((all.get(type) || []) as EventHandlerList).slice().map((handler) => { handler(evt); });
7575
((all.get('*') || []) as WildCardEventHandlerList).slice().map((handler) => { handler(type, evt); });
7676
}

test/index.js renamed to test/index_test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import mitt from '..';
1+
import mitt, { Emitter } from '..';
22
import chai, { expect } from 'chai';
33
import { spy } from 'sinon';
44
import sinonChai from 'sinon-chai';
@@ -23,7 +23,7 @@ describe('mitt', () => {
2323
});
2424

2525
describe('mitt#', () => {
26-
let events, inst;
26+
let events, inst: Emitter;
2727

2828
beforeEach( () => {
2929
events = new Map();
@@ -143,7 +143,7 @@ describe('mitt#', () => {
143143
it('should invoke handler for type', () => {
144144
const event = { a: 'b' };
145145

146-
inst.on('foo', (one, two) => {
146+
inst.on('foo', (one, two?) => {
147147
expect(one).to.deep.equal(event);
148148
expect(two).to.be.an('undefined');
149149
});

test/test-types-compilation.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/* eslint-disable @typescript-eslint/ban-ts-comment, @typescript-eslint/no-unused-vars */
2+
3+
import mitt from '..';
4+
5+
const emitter = mitt();
6+
7+
/*
8+
* Check that if on is provided a generic, it only accepts handlers of that type
9+
*/
10+
{
11+
const badHandler = (x: number) => {};
12+
const goodHandler = (x: string) => {};
13+
14+
// @ts-expect-error
15+
emitter.on<string>('foo', badHandler);
16+
emitter.on<string>('foo', goodHandler);
17+
}
18+
19+
/*
20+
* Check that if off is provided a generic, it only accepts handlers of that type
21+
*/
22+
{
23+
const badHandler = (x: number) => {};
24+
const goodHandler = (x: string) => {};
25+
26+
// @ts-expect-error
27+
emitter.off<string>('foo', badHandler);
28+
emitter.off<string>('foo', goodHandler);
29+
}
30+
31+
32+
/*
33+
* Check that if emitt is provided a generic, it only accepts event data of that type
34+
*/
35+
{
36+
interface SomeEventData {
37+
name: string;
38+
}
39+
// @ts-expect-error
40+
emitter.emit<SomeEventData>('foo', 'NOT VALID');
41+
emitter.emit<SomeEventData>('foo', { name: 'jack' });
42+
}
43+

test/types.ts

Lines changed: 0 additions & 20 deletions
This file was deleted.

tsconfig.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
"compilerOptions": {
44
"noEmit": true,
55
"declaration": true,
6-
"moduleResolution": "node"
6+
"moduleResolution": "node",
7+
"esModuleInterop": true
78
},
8-
"exclude": [
9-
"test"
9+
"include": [
10+
"src/*.ts",
11+
"test/*.ts",
1012
]
1113
}

0 commit comments

Comments
 (0)