简体   繁体   中英

Properly type dynamic functions in a proxy using TypeScript

I have a function that returns a Proxy which uses a get trap to infer functions from multiple objects. Now I need to be able to type these functions, since they are technically known at compile time but TypeScript just can't figure them out. How do make TypeScript recognize these functions to be able to add them to my interface?

interface IObject {
  (): IFunction;
  addAMethod(name: string, fn: (...args: any[]) => any): void;
}

interface IFunction {
  list: string[];
  option: boolean;
}

const mainFunc: IObject = Object.assign(
  (): IFunction => {
    const context = {
      list: [],
      option: true,
    };

    return new Proxy(context, handler);
  },
  {
    addAMethod(name: string, fn: (...args: any[]) => any) {
      Object.assign(core, fn);
    },
  },
);

const handler = {
  get(context: {[key: string]: any}, prop: string, receiver: IFunction) {
    if (prop in context) {
      return context[prop];
    }
    if (prop in core) {
      return core[prop];
    }
  },
};

const core = {
  evaluate: (val: any) => true,
  doSomething: (val: any) => false
}

export default mainFunc;

Now this would allow one to the following:

import mainFunc from "./mainFunc"

mainFunc().evaluate('wow'); // Should return true

This of course does not return true but rather shows that evaluate() is not part of type IFunction , which is true. But when I try to add it I get another error, where I can't assign the function to IFunction because it does not define evaluate() .

// ...

interface IFunction {
  list: string[];
  option: boolean;
  evaluate(val: any): boolean;
}

const mainFunc: IObject = Object.assign(
  (): IFunction => {
    const context = {
      list: [],
      option: true,
    };

    return new Proxy(context, handler); // Error happens here
  },
  // ...
);

// ...

const core = {
  evaluate: (val: any) => true,
  doSomething: (val: any) => false
}

Type '{ list: never[]; option: boolean; }' is not assignable to type 'IFunction'. Property 'evaluate' is missing in type '{ list: never[]; option: boolean; }'.

Any idea how I could type evaluate() ?

The problem is that the TypeScript typings for the Proxy constructor assumes that the proxy will be the same type as the target parameter , even though this is not always true. There is an open issue asking for community help in coming up with better typings.

In the absence of that, I think the only way to deal with this is going to be the judicious use of type assertions and the any type. For example, you can change the line with the error to:

return new Proxy(context, handler) as IFunction;

and that will probably silence the error. It's not fully type safe, but as long as you're sure about what you're doing, it should be fine. And you should be able to add that evaluate() method to the IFunction interface too.

Hope that helps; good luck!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM