Typescript泛型使用函数参数作为可选参数

时间:2019-11-21 08:53:36

标签: typescript typescript-generics

我正在尝试将api调用通过管道传递给通用方法。.我需要能够推断出参数,以便可以键入dispatch方法。

如果要使用Parameters<T[K]>类型,则需要使用所有dispatcher.dispatch(["this is my data", ... ])这样的参数进行调度调用,这也不是主要问题。

主要问题是,我无法一般性地推断参数是否可选。.因此,在下面的示例中,dispatcher.dispatch()中断了。

class Dispatcher<T extends object, K extends FunctionKeys<T>, P = T[K] extends (p1: infer P) => void ? P : never> {

    private readonly method: K;
    private readonly filter: (listener: any) => boolean;
    private readonly listenerResolver: () => any[];

    constructor(method: K, listenerResolver: () => any[]) {
        this.method = method;
        this.listenerResolver = listenerResolver;
        this.filter = (listener: any) => !!listener[this.method];
    }

    dispatch(arg: P) {
        const listeners = this.listenerResolver();
        listeners.filter(this.filter).forEach((listener: T) => listener[this.method](arg));
    }
}

interface Listener {
    action(data?: string): void;
}


const dispatcher = new Dispatcher<Listener, "action">("action", () => []);

dispatcher.dispatch("this is my data");
dispatcher.dispatch(); // this line does not compile

有想法吗?

1 个答案:

答案 0 :(得分:0)

技巧是为dispatch方法的参数创建条件类型。 完整代码(由于您的代码段不完整,我替换了某些类型:

class Dispatcher<T extends object, K extends keyof T, P = T[K] extends (p1: infer P) => void ? P : never> {

    private readonly method: K;
    private readonly filter: (listener: any) => boolean;
    private readonly listenerResolver: () => Record<K, Function>[];

    constructor(method: K, listenerResolver: () => Record<K, Function>[]) {
        this.method = method;
        this.listenerResolver = listenerResolver;
        this.filter = (listener: any) => !!listener[this.method];
  }
  // below solution
  dispatch(...arg: P extends undefined ? [] : [P]) {
      const listeners = this.listenerResolver();
      listeners.filter(this.filter).forEach((listener) => listener[this.method](arg));
  }
}

interface Listener {
    action(data?: string): void;
}


const dispatcher = new Dispatcher<Listener, "action">("action", () => []);

dispatcher.dispatch("this is my data");
dispatcher.dispatch(); // this line compiles :)

该解决方案在dispatch方法参数类型中可见:

...arg: P extends undefined ? [] : [P]

我们说的是,如果P扩展了undefined,并且可选属性也是如此,则参数列表为空[],因此没有参数,但是如果有一个非可选参数,那么这是必需的。希望能帮助到你。