I have a function that takes an object of other functions:
const fn = <T extends Record<string, (...args: any) => Promise<unknown>>>(
t: T
) => {
// code for binding `this` context for `t` variable methods.
};
I would like to extend this context of methods passed to fn with a few properties having the ability to access other methods from this at the same time (foo and bar in the example):
fn({
async foo() {},
async bar() {
this.foo // should reference foo function
this.propertyA // should point to custom bound property
},
});
I've tried something like that, but T seems to be unknown when used inside of its own definition, so original context is lost and I have only { propertyA: string } as this type:
const fn = <
T extends Record<
string,
(this: T & { propertyA: string }, ...args: any) => Promise<unknown>
>
>(
t: T
) => {};
fn({
async foo() {},
async bar() {
this.foo // not available
this.propertyA // available
},
});
CodePudding user response:
To get the sort of inference you're looking for, you need to use the special "magical"/intrinsic ThisType<T> utility type:
const fn = <T extends Record<keyof T, (...args: any) => Promise<unknown>>>(
t: T & ThisType<T & { propertyA: string }>
) => { };
fn({
async foo(x: number) { },
async bar() {
this.foo(3) // this works
this.propertyA.toUpperCase(); // this too
},
});
Your version, with a this parameter, ends up requiring that the methods have such a this context, but does not infer it. Whereas ThisType<T> produces a contextual type for methods in which this is inferred how you want. And note that ThisType<T> is "magical"; it is granted this inference behavior by the compiler itself and can't be re-implemented by user code.
