首页 > 解决方案 > 在 Node.js 中使用 EventEmitter 和 Typescript 的类型安全侦听器

问题描述

给定一个Typescript接口和一个扩展Node.js EventEmitter的类,是否可以定义自定义侦听器来对函数参数进行类型安全检查?

给定以下示例:

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
        });
    }
}

节点 EventEmitter 侦听器定义为(...args: any[]) => void),我想覆盖any[]类型并改用自定义类型。是否可以?

标签: javascriptnode.jstypescripteventemitter

解决方案


是的,有一个很棒的包叫做Typed-Emitter(链接到项目)对我来说非常有用。

从他们的文档中:

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>) {
  // ...
}

对于您的示例,这应该有效:


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
        });
    }
}

推荐阅读