首先,我是Typescript的新手,因此标题可能不准确,因为我不知道该代码如何正常工作。
我正在使用Klasa framework,这是一个以Discord为基础的Discord.js机器人框架。他们最近添加了插件功能,并且有许多用常规ES6编写的示例...
const { Client, util: { mergeDefault } } = require('klasa');
const DriverStore = require('../lib/structures/DriverStore');
const { OPTIONS } = require('../lib/util/constants');
class MusicClient extends Client {
constructor(config) {
super(config);
this.constructor[Client.plugin].call(this);
}
static [Client.plugin]() {
mergeDefault(OPTIONS, this.options);
this.drivers = new DriverStore(this);
this.registerStore(this.drivers);
}
}
module.exports = MusicClient;
Client.plugin
的类型是Symbol。该代码如何工作?以及如何使用TypeScript达到类似目的或可行?
我试图这样做:
import { KlasaClientOptions, Client } from "klasa"
export class ExtendedClient extends Client {
public prop: string;
constructor(options: KlasaClientOptions) {
super(options);
// Element implicitly has an 'any' type 'typeof KlasaClient' has no index signature.
this.constructor[Client.plugin].call(this);
// Also trying to use ExtendedClient.plugin.call() gives me
// Property 'call' does not exist on type 'symbol'
}
static [Client.plugin]() {
// Property 'prop' does not exist of type 'typeof ExtendedClient'
this.prop = "somestring";
}
}
编辑:发现static [Client.plugin]()
具有KlasaClient
的上下文后,我修复了错误,因此将其更改为
import { KlasaClientOptions, Client } from "klasa"
export class ExtendedClient extends Client {
public prop: string;
constructor(options: KlasaClientOptions) {
super(options);
(this.constructor as any)[Client.plugin].call(this);
}
static [Client.plugin](this: ExtendedClient) {
this.prop = "somestring";
}
}
问题已经解决...
答案 0 :(得分:0)
代码相当奇怪,除非存在 strong 设计约束,否则它不是最佳实践。
它正在定义一个static
方法,但是将其当作实例方法来调用。这就是TypeScript遇到问题的部分原因。
关键部分是:
此:
static [Client.plugin]() {
this.registerStore(this.drivers);
}
...它定义了一个静态方法(构造函数上的方法),其名称来自Client.plugin
(您说过是Symbol,但实际上是Symbol还是字符串)。
这在构造函数中:
this.constructor[Client.plugin].call(this);
...这就是所谓的实例方法。 this.constructor
访问创建了this
的构造函数(松散地说,这并不完全准确),因此this.constructor[Client.plugin]
使用名称为Client.plugin
的静态方法进行访问。然后.call(this)
调用该方法,但在调用过程中将this
设置为this
,尽管它是一个实例方法。因此,在对Client.plugin
的调用中,this
是该类的 instance (而通常this
将是构造函数)。
这很奇怪。
在使TypeScript正常运行方面,我想我可能会这样处理:
import { KlasaClientOptions, Client } from "klasa";
export class ExtendedClient extends Client {
public prop: string;
constructor(options: KlasaClientOptions) {
super(options);
(this.constructor as any)[Client.plugin].call(this);
}
static [Client.plugin]() {
const inst = this as ExtendedClient;
// Now use `inst` instead of `this` where your example code uses `this`, so:
inst.prop = "somestring";
}
}
关键位是:
此:
(this.constructor as any)[Client.plugin].call(this);
...通过使用any
,我们击败了TypeScript的类型检查,但基本上必须使用这种奇怪的结构。
这:
const inst = this as ExtendedClient;
...通过使用as ExtendedClient
,我们告诉TypeScript尽管通常希望this
是构造函数,但实际上是ExtendedClient
。我们使用常量一次来执行此操作,以避免不得不在任何地方重复它。