使用泛型限制参数

问题

首先我们定义一个 Event 对象

export type Event =
  | {
      type: 'CLICK';
    }
  | {
      type: 'INPUT';
      payload: {
        value: string;
      };
   };

然后有这么一个函数

const sendEvent = (type: string, payload?: any) => {
  // 具体方法的实现
};

我们预期这个函数应该是这样调用的:

sendEvent('CLICK');
sendEvent('INPUT', {
  value: '123',
});

由于这个类型定义的比较宽泛,所以导致这个方法可以随意调用:

// should error
sendEvent('lalalala');
sendEvent('CLICK', 'aaa');
sendEvent('INPUT');
sendEvent('INPUT', {
  value: 123,
});

所以我们需要重新定义下这个函数的参数类型。

剧透预警线

解答

我们可以通过 infer 来根据第一个参数来推断出第二个参数的类型:

const sendEvent = <T extends Event['type']>(
  ...args: Extract<Event, { type: T }> extends { payload: infer Tpaylad }
    ? [type: T, payload: Tpaylad]
    : [type: T]
) => {};

知识点

  1. infer
  2. Extract