如何调用计算的继承符号!作为扩展类中的功能?

时间:2018-12-01 09:06:26

标签: javascript typescript

首先,我是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";
    }

}

问题已经解决...

1 个答案:

答案 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。我们使用常量一次来执行此操作,以避免不得不在任何地方重复它。