How to redefine return types for methods with Proxy in Typescript

Viewed 99

I'm trying to promisify all methods in a class with Proxy like this:

class Person {
  id = 1
  getName(): string {
    return "name"
  }

  getAge(): number {
    return 1
  }
}

const person = new Person();

const asyncPerson = new Proxy(person, {
  get(target, prop, receiver) {
    let fn = Reflect.get(target, prop, receiver)
    if (typeof fn !== 'function') {
      return fn
    }
    return (...args: any[]) => {
      return new Promise((res, rej) => {
        try {
          res(fn.apply(receiver, args))
        } catch (err) {
          rej(err)
        }
      }) 
    }
    
  }
})

console.log(asyncPerson.id)
console.log(asyncPerson.getName())

The problem is that typescript thinks asyncPerson is of type Person. Any way to define a new type that correctly reflects the type of asyncPerson without having to manually type out all Person's methods?

OTOH, is there a way to automatically define a "promisified" class?

1 Answers

You can use conditional types to create a "promisified" version of a type:

type Promisified<T> = { 
    [K in keyof T]: T[K] extends (...args: infer A) => infer R
        ? (...args: A) => Promise<R>
        : T[K] 
};

The above utility will wrap the return type of methods with promise.

Another caveat is that Proxy constructor definition always returns the same as the input type. To overcome this new Proxy<any> can be used or double type assertion.

Playground

Related