问题
Given a Typescript interface and a class extending Node.js EventEmitter, is it possible to define custom listeners that give typesafe check for the function arguments?
Given the following example:
import { EventEmitter } from 'events';
interface Payload {
id: string;
weight: number;
}
class CustomEventEmitter extends EventEmitter {
constructor() {
super();
this.on('my_event', (data) => {
// I would like data to be implicitly inferred as Payload type
console.log(data.weight); // This should compile
console.log(data.something); // This should not compile
});
}
}
A node EventEmitter listener is defined as (...args: any[]) => void)
, I would like to override the any[]
type and use custom defined types instead. Is it possible?
回答1:
Yep, there's an awesome package called Typed-Emitter (link to project) that works really well for me.
From their docs:
import {EventEmitter} from "events" // I made a slight change here as I've needed to explicitly import EventEmitter from events
import TypedEmitter from "typed-emitter"
// Define your emitter's types like that:
// Key: Event name; Value: Listener function signature
interface MessageEvents {
error: (error: Error) => void,
message: (body: string, from: string) => void
}
const messageEmitter = new EventEmitter() as TypedEmitter<MessageEvents>
// Good 👍
messageEmitter.emit("message", "Hi there!", "no-reply@test.com")
// TypeScript will catch those mistakes ✋
messageEmitter.emit("mail", "Hi there!", "no-reply@test.com")
messageEmitter.emit("message", "Hi there!", true)
// Good 👍
messageEmitter.on("error", (error: Error) => { /* ... */ })
// TypeScript will catch those mistakes ✋
messageEmitter.on("error", (error: string) => { /* ... */ })
messageEmitter.on("failure", (error: Error) => { /* ... */ })
class MyEventEmitter extends (EventEmitter as new () => TypedEmitter<MyEvents>) {
// ...
}
For your example, this should work:
import { EventEmitter } from 'events';
import TypedEmitter from "typed-emitter"
interface Payload {
id: string;
weight: number;
}
interface CustomEventEmitterEvents {
my_event: (data: Payload) => void
}
class CustomEventEmitter extends (EventEmitter as new () => TypedEmitter<CustomEventEmitterEvents>) {
constructor() {
super();
this.on('my_event', (data) => {
// I would like data to be implicitly inferred as Payload type
console.log(data.weight); // This should compile
console.log(data.something); // This should not compile
});
}
}
来源:https://stackoverflow.com/questions/63649104/typesafe-listeners-using-eventemitter-and-typescript-in-node-js