Typescript:重写超类方法而不需要知道超类方法签名

发布于 2025-01-18 19:42:43 字数 1916 浏览 0 评论 0原文

以下是我如何可靠地重写普通 JS 中的方法,而不关心名称或参数数量或返回值:

import EventEmitter from 'events'

// console.log event + arguments every time this emitter emits anything.
// Just an example.  
class LogEmitter extends EventEmitter {
  emit(...args) {
    console.log('emit', ...args)
    return super.emit(...args)
  }
}

但在 TypeScript 中,我听到抱怨:

import { EventEmitter } from 'events'

class LogEmitter extends EventEmitter {
  emit(...args) {                // Rest Parameter 'args' implicitly has an any[] type
    console.log('emit', ...args)
    return super.emit(...args)  // Expected at least 1 arguments, but got 0 or more.
  }
}

我不确定如何告诉 TypeScript 这是可以的。我不想知道有关我要重写的方法的签名的任何信息,只需打印您传递的任何参数即可。意味着如果/当超类签名发生更改时,我不必更新我的签名,理想情况下,我将有一种方法来键入它,该方法适用于我重写的所有方法,也许有一个例外,告诉它要复制哪个方法名称签名来自.

像这样的东西:

...args 的类型应该与 super.emitParameters 相同

但是我的新手尝试这不是有效的语法:

import { EventEmitter } from 'events'

class LogEmitter extends EventEmitter {
  emit(...args: Parameters<super.emit>) {  // 'super' can only be referenced in members of derived classes or object literal expressions.
    console.log('emit', ...args)
    return super.emit(...args)
  }
}

我的解决方法是 any 所需的第一个参数:

import { EventEmitter } from 'events'

class LogEmitter extends EventEmitter {
  emit(type: any, ...args: any[]) {
    console.log('emit', type, ...args)
    return super.emit(type, ...args)
  }
}

但我认为这更像是修补症状,因为现在此类报告的签名不太准确。我觉得有一个更好的解决方案,可以自动为emit提供正确的签名,而无需我从super.emit复制它。

我该如何做完美地输入此内容,而无需了解有关 super.emit 签名的任何信息?

Here's how I would reliably override a method in vanilla JS without caring about names or number of arguments, or the return value:

import EventEmitter from 'events'

// console.log event + arguments every time this emitter emits anything.
// Just an example.  
class LogEmitter extends EventEmitter {
  emit(...args) {
    console.log('emit', ...args)
    return super.emit(...args)
  }
}

But in TypeScript, I hear complaints:

import { EventEmitter } from 'events'

class LogEmitter extends EventEmitter {
  emit(...args) {                // Rest Parameter 'args' implicitly has an any[] type
    console.log('emit', ...args)
    return super.emit(...args)  // Expected at least 1 arguments, but got 0 or more.
  }
}

I'm not sure how to tell TypeScript that this is ok. I don't want to know anything about the signature of the method I'm overriding, just print whatever arguments you're passed. Means I don't have to update my signature if/when the superclass signature changes, and ideally I would have one way to type this that would work for all methods I override, with maybe an exception of telling it which method name to copy the signature from.

Something like:

The type of ...args should be whatever the Parameters are to super.emit

But my newbie attempt at this isn't valid syntax:

import { EventEmitter } from 'events'

class LogEmitter extends EventEmitter {
  emit(...args: Parameters<super.emit>) {  // 'super' can only be referenced in members of derived classes or object literal expressions.
    console.log('emit', ...args)
    return super.emit(...args)
  }
}

My workaround is to any the required first argument:

import { EventEmitter } from 'events'

class LogEmitter extends EventEmitter {
  emit(type: any, ...args: any[]) {
    console.log('emit', type, ...args)
    return super.emit(type, ...args)
  }
}

But I think this is more like patching symptoms, since now this class reports a less accurate signature. I feel like there's a better solution that gives the correct signature for emit automatically without me having to copy it from super.emit.

How can I type this perfectly without having to know anything about the signature of super.emit?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

风蛊 2025-01-25 19:42:43

不幸的是,Typescript 不(从 TS4.1 开始)上下文类型 子类成员由超类(或实现的接口)中的类似成员组成。有很多类似的 GitHub 问题,但我认为这种特殊情况的规范问题是 microsoft/ TypeScript#23911。目前,您所能做的就是“修补症状”:

作为一种解决方法,如果您想引用超类,则需要通过名称 (EventEmitter) 显式执行此操作,而不是通过 < code>super,并且您可以使用 查找类型以获取emit方法:

class LogEmitter extends EventEmitter {
  emit(...args: Parameters<EventEmitter['emit']>) {
    console.log('emit', ...args)
    return super.emit(...args)
  }
}

Playground 代码链接

Unfortunately, Typescript does not (as of TS4.1) contextually type subclass members by the analogous members in super classes (or implemented interfaces). There are a bunch of similar GitHub issues, but I think the canonical one for this particular situation is microsoft/TypeScript#23911. For now, all you can do is "patch symptoms":

As a workaround, if you want to refer to the super class, you will need to do so explicitly by name (EventEmitter) and not by super, and you can use a lookup type to get the emit method:

class LogEmitter extends EventEmitter {
  emit(...args: Parameters<EventEmitter['emit']>) {
    console.log('emit', ...args)
    return super.emit(...args)
  }
}

Playground link to code

千鲤 2025-01-25 19:42:43

typeof fn允许您获取函数的类型,因此parameters&lt; type eventemitter.prototype.emit&gt;应该使事物工作。

typeof fn lets you get the type of a function, so Parameters<typeof EventEmitter.prototype.emit> should get things working.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文