类方法的隐式`this`类型

Mud*_*Mud 9 typescript

编辑:这似乎是Typescript中的一个已知问题.一个解决方案一旦实施,但由于无法解决的性能问题而最终被解决.

这种情况通常出现在我们的代码库中:

function consumer<T>(valueProducer: () => T) {
    let value = valueProducer();
    console.log(value);
}

class Foo {
    private _value: number = 100;

    getValue(): number {
        return this._value;
    }

    constructor() {
        // Oops! Inside consumer(), getValue will be called with wrong this
        consumer(this.getValue);
    }
}
Run Code Online (Sandbox Code Playgroud)

Typescript中的解决方案是这样的:

consumer( () => this.getValue() ); // capture correct this
Run Code Online (Sandbox Code Playgroud)

或这个:

consumer( this.getValue.bind(this) ); // bind to correct this
Run Code Online (Sandbox Code Playgroud)

这个问题对于Typescript/Javascript程序员来说可能是显而易见的,但是我们的团队正在将大量的C#移植到Typescript,而在C#中这不是错误(即C#中传递的方法自动绑定到对象实例).所以我希望类型系统能够捕获此错误,如果可能的话.

显式键入this回调使用的第一个明显的步骤:

function consumer<T>(valueProducer: (this: void) => T) {
    let value = valueProducer();
    console.log(value);
}
Run Code Online (Sandbox Code Playgroud)

我希望这足够了,但事实证明我还需要this在Foo方法上显式输入参数:

class Foo {
    getValue(this: Foo): number { // I could also have written getValue(this: this)
        return this._value;
    }
Run Code Online (Sandbox Code Playgroud)

有了这两件事,我现在得到了我想要的错误:

error TS2345: Argument of type '(this: Foo) => number' is not assignable to parameter of type '(this: void) => number'.
  The 'this' types of each signature are incompatible.
    Type 'void' is not assignable to type 'Foo'.
Run Code Online (Sandbox Code Playgroud)

但是,我不想添加this: this到我的应用程序中的每个方法.this方法中的值是否应该隐含为封闭类型的值?是否有另一种方法可以实现相同的结果,而不会将所有样板噪声添加到我的类中?

(讨论代码的plunker)

Mat*_*247 0

您可以将this参数显式传递给回调,就像内置的 javascript 函数map也支持显式一样this

function consumer<T>(valueProducer: () => T, thisArg: any) {
    let value = valueProducer.apply(thisArg);
    console.log(value);
}

class Foo {
    private _value: number = 100;

    getValue(): number {
        return this._value;
    }

    constructor() {
        consumer(this.getValue, this);
    }
}
Run Code Online (Sandbox Code Playgroud)

从我的角度来看,它比箭头函数方法更难看,但至少你不能忘记传递它。