diff options
| author | Jack Franklin <[email protected]> | 2020-07-15 15:31:43 +0100 |
|---|---|---|
| committer | GitHub <[email protected]> | 2020-07-15 10:31:43 -0400 |
| commit | 5116df46a020ae498eec6783cfe9147fc9add015 (patch) | |
| tree | 93be70d93df33d1d60c7c3e4cfed0ae408e272cb | |
| parent | 244cac2aa3d6831774129d6dc4942465dcef8099 (diff) | |
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]>
| -rw-r--r-- | .editorconfig | 1 | ||||
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | README.md | 2 | ||||
| -rw-r--r-- | package.json | 35 | ||||
| -rw-r--r-- | src/index.ts | 14 | ||||
| -rw-r--r-- | test/index_test.ts (renamed from test/index.js) | 6 | ||||
| -rw-r--r-- | test/test-types-compilation.ts | 43 | ||||
| -rw-r--r-- | test/types.ts | 20 | ||||
| -rw-r--r-- | tsconfig.json | 8 |
9 files changed, 86 insertions, 44 deletions
diff --git a/.editorconfig b/.editorconfig index ac0adb7..04d7ef9 100644 --- a/.editorconfig +++ b/.editorconfig @@ -10,6 +10,7 @@ insert_final_newline = true [{package.json,.*rc,*.yml}] indent_style = space indent_size = 2 +insert_final_newline = false [*.md] trim_trailing_whitespace = false @@ -2,6 +2,7 @@ /test-reports /node_modules /npm-debug.log +/index.d.ts package-lock.json .DS_Store .idea @@ -110,7 +110,7 @@ const emitter: mitt.Emitter = mitt(); Mitt: Tiny (~200b) functional event emitter / pubsub. -Returns **Mitt** +Returns **Mitt** ### on diff --git a/package.json b/package.json index 90b7b74..a2c2b58 100644 --- a/package.json +++ b/package.json @@ -8,12 +8,13 @@ "esmodules": "dist/mitt.modern.js", "main": "dist/mitt.js", "umd:main": "dist/mitt.umd.js", - "typings": "dist/index.d.ts", + "typings": "index.d.ts", "scripts": { - "test": "npm-run-all --silent typecheck lint testonly", - "testonly": "mocha --require esm test/**/*.js", + "test": "npm-run-all --silent typecheck lint mocha test-types", + "mocha": "mocha test", + "test-types": "tsc test/test-types-compilation.ts --noEmit", "lint": "eslint src test --ext ts --ext js", - "typecheck": "tsc **/*.ts --noEmit", + "typecheck": "tsc --noEmit", "bundle": "microbundle", "build": "npm-run-all --silent clean -p bundle -s docs", "clean": "rimraf dist", @@ -34,8 +35,21 @@ "license": "MIT", "files": [ "src", - "dist" + "dist", + "index.d.ts" ], + "mocha": { + "extension": [ + "ts" + ], + "require": [ + "ts-node/register", + "esm" + ], + "spec": [ + "test/*_test.ts" + ] + }, "eslintConfig": { "extends": [ "developit", @@ -68,7 +82,8 @@ } }, "eslintIgnore": [ - "dist" + "dist", + "index.d.ts" ], "devDependencies": { "@types/chai": "^4.2.11", @@ -82,13 +97,13 @@ "eslint": "^7.1.0", "eslint-config-developit": "^1.2.0", "esm": "^3.2.25", - "microbundle": "^0.12.0", - "mocha": "^7.2.0", + "microbundle": "^0.12.3", + "mocha": "^8.0.1", "npm-run-all": "^4.1.5", "rimraf": "^3.0.2", "sinon": "^9.0.2", "sinon-chai": "^3.5.0", - "ts-node": "^8.10.1", + "ts-node": "^8.10.2", "typescript": "^3.9.3" } -} +}
\ No newline at end of file diff --git a/src/index.ts b/src/index.ts index e640292..c681fd0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,8 +2,8 @@ export type EventType = string | symbol; // An event handler can take an optional event argument // and should not return a value -export type Handler = (event?: any) => void; -export type WildcardHandler = (type: EventType, event?: any) => void +export type Handler<T = any> = (event?: T) => void; +export type WildcardHandler = (type: EventType, event?: any) => void; // An array of all currently registered event handlers for a type export type EventHandlerList = Array<Handler>; @@ -13,10 +13,10 @@ export type WildCardEventHandlerList = Array<WildcardHandler>; export type EventHandlerMap = Map<EventType, EventHandlerList | WildCardEventHandlerList>; export interface Emitter { - on(type: EventType, handler: Handler): void; + on<T = any>(type: EventType, handler: Handler<T>): void; on(type: '*', handler: WildcardHandler): void; - off(type: EventType, handler: Handler): void; + off<T = any>(type: EventType, handler: Handler<T>): void; off(type: '*', handler: WildcardHandler): void; emit<T = any>(type: EventType, event?: T): void; @@ -38,7 +38,7 @@ export default function mitt(all?: EventHandlerMap): Emitter { * @param {Function} handler Function to call in response to given event * @memberOf mitt */ - on(type: EventType, handler: Handler) { + on<T = any>(type: EventType, handler: Handler<T>) { const handlers = all.get(type); const added = handlers && handlers.push(handler); if (!added) { @@ -53,7 +53,7 @@ export default function mitt(all?: EventHandlerMap): Emitter { * @param {Function} handler Handler function to remove * @memberOf mitt */ - off(type: EventType, handler: Handler) { + off<T = any>(type: EventType, handler: Handler<T>) { const handlers = all.get(type); if (handlers) { handlers.splice(handlers.indexOf(handler) >>> 0, 1); @@ -70,7 +70,7 @@ export default function mitt(all?: EventHandlerMap): Emitter { * @param {Any} [evt] Any value (object is recommended and powerful), passed to each handler * @memberOf mitt */ - emit(type: EventType, evt: any) { + emit<T = any>(type: EventType, evt: T) { ((all.get(type) || []) as EventHandlerList).slice().map((handler) => { handler(evt); }); ((all.get('*') || []) as WildCardEventHandlerList).slice().map((handler) => { handler(type, evt); }); } diff --git a/test/index.js b/test/index_test.ts index a837d36..1f1d9bb 100644 --- a/test/index.js +++ b/test/index_test.ts @@ -1,4 +1,4 @@ -import mitt from '..'; +import mitt, { Emitter } from '..'; import chai, { expect } from 'chai'; import { spy } from 'sinon'; import sinonChai from 'sinon-chai'; @@ -23,7 +23,7 @@ describe('mitt', () => { }); describe('mitt#', () => { - let events, inst; + let events, inst: Emitter; beforeEach( () => { events = new Map(); @@ -143,7 +143,7 @@ describe('mitt#', () => { it('should invoke handler for type', () => { const event = { a: 'b' }; - inst.on('foo', (one, two) => { + inst.on('foo', (one, two?) => { expect(one).to.deep.equal(event); expect(two).to.be.an('undefined'); }); diff --git a/test/test-types-compilation.ts b/test/test-types-compilation.ts new file mode 100644 index 0000000..00510da --- /dev/null +++ b/test/test-types-compilation.ts @@ -0,0 +1,43 @@ +/* eslint-disable @typescript-eslint/ban-ts-comment, @typescript-eslint/no-unused-vars */ + +import mitt from '..'; + +const emitter = mitt(); + +/* + * Check that if on is provided a generic, it only accepts handlers of that type + */ +{ + const badHandler = (x: number) => {}; + const goodHandler = (x: string) => {}; + + // @ts-expect-error + emitter.on<string>('foo', badHandler); + emitter.on<string>('foo', goodHandler); +} + +/* + * Check that if off is provided a generic, it only accepts handlers of that type + */ +{ + const badHandler = (x: number) => {}; + const goodHandler = (x: string) => {}; + + // @ts-expect-error + emitter.off<string>('foo', badHandler); + emitter.off<string>('foo', goodHandler); +} + + +/* + * Check that if emitt is provided a generic, it only accepts event data of that type + */ +{ + interface SomeEventData { + name: string; + } + // @ts-expect-error + emitter.emit<SomeEventData>('foo', 'NOT VALID'); + emitter.emit<SomeEventData>('foo', { name: 'jack' }); +} + diff --git a/test/types.ts b/test/types.ts deleted file mode 100644 index 23334bb..0000000 --- a/test/types.ts +++ /dev/null @@ -1,20 +0,0 @@ -import mitt, { EventHandlerList, EventHandlerMap } from '..'; - -const events = mitt(); -function foo() {} -events.on('foo', foo); -events.emit('foo', 'hello'); - -// handler return type should be ignored: -events.on('foo', async e => e * 42); - -// event map type -const map = new Map<string, EventHandlerList>([ - ['foo', [foo]] -]); -const events2 = mitt(map); -events2.emit('foo', 'hello'); - -// event map type & iterables -const map2 : EventHandlerMap = new Map(Object.entries(({ foo: [foo] }))); -mitt(map2); diff --git a/tsconfig.json b/tsconfig.json index 2610831..acab4f5 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,9 +3,11 @@ "compilerOptions": { "noEmit": true, "declaration": true, - "moduleResolution": "node" + "moduleResolution": "node", + "esModuleInterop": true }, - "exclude": [ - "test" + "include": [ + "src/*.ts", + "test/*.ts", ] } |
