【问题标题】:Adjust `this` context of methods in object passed as a function argument调整作为函数参数传递的对象中方法的“this”上下文
【发布时间】:2020-09-13 08:23:30
【问题描述】:

我在将 this 上下文更新为作为参数传递的对象方法时遇到问题。

function decorate<T extends {
    [K in keyof T]: T[K] extends (this: infer This, ...args: infer Args) => infer Return
        ? (this: This & { abc: 10 }, ...args: Args) => Return
        : never;
}>(object: T) {
    // @ts-ignore: just a hack to show a simple example
    object.abc = 10;
    return object;
}

decorate({
   getString() { return "abc"; },
   doSomething() {
       const str: string = this.getString(); // Property 'getString' does not exist on type '{ abc: 10; }'.(2339)
       const abc: number = this.abc;
   }
});

TypeScript 正确检测到 abc,但无法访问原始上下文。深入挖掘,似乎推断出Thisunknown

function decorate<T extends {
    [K in keyof T]: T[K] extends (this: infer This, ...args: infer Args) => infer Return
        ? (this: This, ...args: Args) => Return
        : never;
}>(object: T) {
    // @ts-ignore: just a hack to show a simple example
    object.abc = 10;
    return object;
}

decorate({
   getString() { return "abc"; },
   doSomething() {
       const str: string = this.getString(); // Object is of type 'unknown'. (2571)
       const abc: number = this.abc; // Object is of type 'unknown'. (2571)
   }
});

我尝试直接使用原始对象作为上下文,但此时的T 仅被检测为对象({}),具有未知属性:

function decorate<T extends {
    [K in keyof T]: T[K] extends (...args: infer Args) => infer Return
        ? (this: T, ...args: Args) => Return
        : never;
}>(object: T) {
    // @ts-ignore: just a hack to show a simple example
    object.abc = 10;
    return object;
}

decorate({
   getString() { return "abc"; },
   doSomething() {
       const str: string = this.getString(); // Property 'getString' does not exist on type '{}'. (2339)
       const abc: number = this.abc; // Property 'abc' does not exist on type '{}'. (2339)
   }
});

有没有办法调整传递对象的方法的上下文,或者可能有完全不同的方式来达到类似的效果?

【问题讨论】:

    标签: typescript types casting typescript-generics


    【解决方案1】:

    我认为你最好的选择是使用ThisType。这是编译器的一个特殊标记接口,允许您轻松指定this 的含义。当您将对象分配给类型为 ThisType&lt;T&gt; 的位置时,T 被认为是该对象中定义的任何方法/函数的 this 类型。

    有了这个,解决你的问题就变得很简单了:

    function decorate<T>(object: T & ThisType<T & { abc: number }>) {
        return Object.assign( object, { abc:  10 });
    }
    
    decorate({
       getString() { return "abc"; },
       doSomething() {
           const str: string = this.getString(); // Property 'getString' does not exist on type '{}'. (2339)
           const abc: number = this.abc; // Property 'abc' does not exist on type '{}'. (2339)
       }
    });
    

    Playground Link

    【讨论】:

    • 谢谢,我不知道 ThisType 标记,它就像一个魅力!
    猜你喜欢
    • 2013-01-22
    • 1970-01-01
    • 1970-01-01
    • 2018-05-02
    • 2015-06-30
    • 1970-01-01
    • 2020-09-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多