基于函数参数的 TypeScript 动态函数定义

TypeScript dynamic Function definition based on functions argument

是否可以根据传递给函数的参数值更改某些东西的类型。对于带有回调的事件发射器,我需要这种类型。示例:

interface IUser {
  name: string
}

type CallBack = /* the Type for the Callback that should be dynamic */

//for event1 the type CallBack should be (user: IUser) => any
use("event1", (user) => { /* check that event1 is used, so only add 1 argument to the callback type  */ })

//for event2 the type CallBack should be (email: string, password: string) => any
use("event2", (email, password) => { /* check that event12is used, so add 2 argument to the callback type */ })

那么有没有办法检测使用了哪个事件并将正确的类型应用于回调?

最简单的方法是重载。


type CallBack = {
  (name: "event1", cb: (u: IUser) => void): void
  (name: "event2", cb: (email:string, pass: string) => void): void
}

let use: CallBack = null!;
//for event1 the type CallBack should be (user: IUser) => any
use("event1", (user) => { /* check that event1 is used, so only add 1 argument to the callback type  */ })

//for event2 the type CallBack should be (email: string, password: string) => any
use("event2", (email, password) => { /* check that event12is used, so add 2 argument to the callback type */ })

Playground Link

如果您有更复杂的场景,例如已经有其他类型的回调,或者更复杂的条件,您可以考虑在剩余参数和条件类型中使用元组。但是从你的问题来看,那太过分了。

您可以使用这样的类型:

type CallBackEvent1 = (event: "event1", cb: (user: IUser) => void) => void;
type CallBackEvent2 = (
  event: "event2",
  cb: (email: string, pass: string) => void
) => void;

type CallBack = CallBackEvent1 | CallBackEvent2;

const callBack1: CallBack = (event: "event1", cb: (user: IUser) => void) =>
  undefined;
const callBack2: CallBack = (
  event: "event2",
  cb: (email: string, pass: string) => void
) => undefined;

const wrongCallBack: CallBack = (event: "event2", cb: (user: IUser) => void) =>
  undefined;
// Type '(event: "event2", cb: (user: IUser) => void) => undefined' is not assignable to type 'CallBack'.
//   Type '(event: "event2", cb: (user: IUser) => void) => undefined' is not assignable to type 'CallBackEvent1'.
//     Types of parameters 'event' and 'event' are incompatible.
//       Type '"event1"' is not assignable to type '"event2"'.ts(2322)