打字稿类型:根据其他参数检查正确的回调类型

时间:2020-04-14 16:46:24

标签: typescript generics typescript-generics

我有一个JS函数

const fn = (cb, param) => {
  cb(param);
};

在TS中将被称为2种方式:

const cb0 = () => {};
fn(cb0);

const cb1 = (param: string) => { };
fn(cb1, 'str')

fn的期望通过这种类型正确描述:

interface IFn {
  (cb: (param: string) => void, param: string): void;
  (cb: () => void): void;
}

fnI(cb0); // ok
// fnI(cb1); // correctly does not compile, callback needs an argument
fnI(cb1, 's'); // ok

因此它检查呼叫者站点的类型。但是,我无法将fn转换为Typescript,因此不需要类型转换。此外,由于IFn声明了重载,因此TS似乎拒绝推断参数类型。我能做的最好的是:

const fn: IFn = <IFn>((cb: (param?: string) => void, param?: string) => {
  cb(param);
});

问题是,实现签名的限制较少,以下实现显然违反了IFn的声明,但类型检查程序无法检测到违反。

const fn: IFn = <IFn>((cb: (param?: string) => void, param?: string) => {
  cb(param === undefined ? 'some other string' : undefined);
});

所以问题是: 是否可以定义fn签名或IFn,以便TypeScript可以在实现内部发现上述断言?

很显然,我对运行时检查不感兴趣。

1 个答案:

答案 0 :(得分:0)

尝试一下:

interface IFn {
  (cb: (param: string) => void, param: string): void;
  (cb: () => void): void;
}

const fn: IFn = (
  ...args: [(param: string) => void, string] | [() => void]
) => {
  switch (args.length) {
    case 2: {
      const cb = args[0];
      const param = args[1];

      cb(param);
      break;
    }
    case 1: {
      const cb = args[0];

      cb();
      break;
    }
  }
};

Playground