Home > Mobile >  Extend function "this" object
Extend function "this" object

Time:09-17

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.

Playground link to code

  • Related