0

I'm trying to have a class which partly acts as a Proxy wrapper around some other class, allowing the other class methods to be modified and accept either extra arguments or to change their type.

Let's imagine I have:

class MainClass {
  myMethod(txt: string) {}
  unrelatedProp = "a prop that's not a method"
}

I want to have a class that would look something like this:

class MyHelper {
  mainClass: MainClass; 
  // ... this does a bunch of other stuff not related to `MainClass`
}

const main = new MainClass();
const helper = new MyHelper(main);

helper.myMethod(2) // ← I want to extend `myMethod` to accept, for example, `string | number`.

Firstly, I'm not sure if this is even a thing and there is a better way than using Proxy to do this, but I'm doing this:

type ExtendFirstParamType<T extends (...args: any[]) => any, U>  = [
  Parameters<T>[0] | U,
  ...Parameters<T>
]
// ^^^ First problem here:
// 1. I'll be able to use this type to only extend the first parameter,
// it'd be nice to create a generic which would extend at any index
// 2. I'd need to splice/shift the parameter, instead here I'm spreading
// the rest of the parameters, so I'll get the first parameter again.

class MyHelper {
  constructor(public mainClass: MainClass) {
    const handler = {
      get(target: MainClass, propKey: keyof MainClass) {
        const property = target[propKey];

        if(typeof property !== "function") return property;
        else {
          return (...args: ExtendFirstParamType<typeof property, number>) => {
            // ^^^ Here you can see by hovering that the type is on the right track
            // it correctly infers that the first argument is now `string | number`
            return property.apply(this, args as any);
          }
        }
      }
    }

    this.mainClass = new Proxy(page, handler);
    // ^^^ How would I make sure that this type would be the proxied/extended
    // class? If I don't declare it in my class it complains that it doesn't exist
    // but if I declare it, and type it as `MainClass`, `myMethod` would not have
    // the new proxied type signature

  }
}

Here is a Typescript playground link with what I have so far.

NinGen ShinRa
  • 651
  • 5
  • 16
  • Are you just asking about how to get the types to work? Or are you looking for an implementation too? An implementation could be problematic because I don't see how you can extend an arbitrary method to accept different parameter types and have it still work. I guess I'm wondering how you'd expect such a thing to look in pure JavaScript and then I could imagine giving it types that work. – jcalz Jul 15 '21 at 18:37
  • I'm open to suggestions. I understand I wasn't clear enough about the intention. The intention is to have the method accept different types within the proxy, and the proxy can then manipulate the arguments. In my example case, something that was supposed to accept only `string` could accept a `number` that the proxy turns into a string for the method. In my real-world case, I want to create a seamless wrapper around an existing API over which I have no control, but that would allow a developer with previous knowledge to consume that API with some extended capabilities thanks to proxy magic – NinGen ShinRa Jul 16 '21 at 00:53

0 Answers0