Typesafe listeners using EventEmitter and Typescript in Node.js

眉间皱痕 提交于 2021-01-28 08:02:15

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!