【问题标题】:Typescript types: check for correct callback type depending on other argument打字稿类型:根据其他参数检查正确的回调类型
【发布时间】:2020-06-06 19:22:45
【问题描述】:

我有一个JS函数

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

打算以两种方式调用(在 TS 中):

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,因此它不需要类型转换。此外,似乎 TS 拒绝推断参数类型,因为IFn 声明了重载。我能做的最好的就是:

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 可以发现实现内部的上述断言冲突?

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

【问题讨论】:

  • 您不使用function overloads 有什么原因吗?就此而言,const fn: IFn = (cb: any, param?: string) =&gt; cb(param); 工作正常,世界其他地方只能通过IFn 界面看到它,所以any 无关紧要。
  • @jonrsharpe 感谢您的来信。我认为问题中具有重载的接口相当于链接下的函数重载,但是在我的风格中我使用 const + 箭头函数,因此在这种情况下不清楚如何使用函数重载。另外,问题是如何在我的函数定义中使用类型检查,因为只使用实际定义签名中的类型,所以没有提供哪些函数重载。
  • 我不清楚您在这里遇到了什么问题“在我的函数定义中进行类型检查” 对您意味着什么?您如何看待“实际定义签名”?请edit澄清。
  • @jonrsharpe 重写了问题部分

标签: typescript generics typescript-generics


【解决方案1】:

试试这个:

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

【讨论】:

  • 我只对编译时检查感兴趣。以这种方式转换代码以获得类型安全性会适得其反。
猜你喜欢
  • 2020-07-08
  • 2018-11-03
  • 2019-01-02
  • 2019-07-29
  • 1970-01-01
  • 2019-09-02
  • 2019-11-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多