打字稿:覆盖超类方法而不需要知道超类方法签名
Typescript: Override superclass method without needing to know superclass method signature
以下是我如何可靠地覆盖 vanilla JS 中的方法,而不用关心名称或参数数量,或 return 值:
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 这没问题。我不想知道任何关于我正在覆盖的方法的签名的信息,只需打印您传递的任何参数。意味着我不必更新我的签名 if/when superclass 签名更改,理想情况下,我将有一种方法来键入它,它适用于我重写的所有方法,可能有一个例外它从哪个方法名称复制签名。
类似于:
The type of ...args
should be whatever the Parameters
are to super.emit
但我的新手尝试使用的语法无效:
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)
}
}
但我认为这更像是修补症状,因为现在 class 报告的签名不太准确。我觉得有更好的解决方案可以自动为 提供 emit
的正确签名,而无需我从 super.emit
.
复制它
如何在不了解 任何 super.emit
签名的情况下完美地键入此内容?
typeof fn
可让您获取函数的类型,因此 Parameters<typeof EventEmitter.prototype.emit>
应该可以正常工作。
不幸的是,Typescript 没有(从 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。现在,你能做的就是“补丁症状”:
作为解决方法,如果您想引用超级 class,您将需要通过名称 (EventEmitter
) 而不是 super
明确地这样做,并且您可以使用 lookup type 获取 emit
方法:
class LogEmitter extends EventEmitter {
emit(...args: Parameters<EventEmitter['emit']>) {
console.log('emit', ...args)
return super.emit(...args)
}
}
以下是我如何可靠地覆盖 vanilla JS 中的方法,而不用关心名称或参数数量,或 return 值:
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 这没问题。我不想知道任何关于我正在覆盖的方法的签名的信息,只需打印您传递的任何参数。意味着我不必更新我的签名 if/when superclass 签名更改,理想情况下,我将有一种方法来键入它,它适用于我重写的所有方法,可能有一个例外它从哪个方法名称复制签名。
类似于:
The type of
...args
should be whatever theParameters
are tosuper.emit
但我的新手尝试使用的语法无效:
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)
}
}
但我认为这更像是修补症状,因为现在 class 报告的签名不太准确。我觉得有更好的解决方案可以自动为 提供 emit
的正确签名,而无需我从 super.emit
.
如何在不了解 任何 super.emit
签名的情况下完美地键入此内容?
typeof fn
可让您获取函数的类型,因此 Parameters<typeof EventEmitter.prototype.emit>
应该可以正常工作。
不幸的是,Typescript 没有(从 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。现在,你能做的就是“补丁症状”:
作为解决方法,如果您想引用超级 class,您将需要通过名称 (EventEmitter
) 而不是 super
明确地这样做,并且您可以使用 lookup type 获取 emit
方法:
class LogEmitter extends EventEmitter {
emit(...args: Parameters<EventEmitter['emit']>) {
console.log('emit', ...args)
return super.emit(...args)
}
}