首页 > 解决方案 > 调整作为函数参数传递的对象中方法的“this”上下文

问题描述

我在将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)
   }
});

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

标签: typescripttypescastingtypescript-generics

解决方案


我认为你最好的选择是使用ThisType. 这是编译器的一个特殊标记接口,可让您轻松指定this应表示的含义。当您将对象分配给类型为 的位置时ThisType<T>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)
   }
});

游乐场链接


推荐阅读