【问题标题】:Typescript generics use function params as optional打字稿泛型使用函数参数作为可选
【发布时间】:2020-03-17 03:23:01
【问题描述】:

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

如果我要使用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

想法?

【问题讨论】:

    标签: typescript typescript-generics


    【解决方案1】:

    诀窍是为dispatch 方法的参数创建条件类型。 完整代码(我替换了一些类型,因为您的 sn-p 不完整:

    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,并且可选属性是,那么参数列表是空的[],所以没有参数,但是如果有一个不是可选的参数,那么它是必需的。希望能帮助到你。

    【讨论】:

      猜你喜欢
      • 2022-11-11
      • 2021-05-03
      • 2023-02-22
      • 2018-05-02
      • 2020-03-01
      • 2019-10-18
      • 2021-06-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多