You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为含类式属性的JS函数正确添加TypeScript类型?

正确为带属性的函数定义TypeScript类型

这种在函数上挂载额外属性的场景确实容易让TS新手困惑——毕竟我们通常习惯函数就是函数、对象就是对象,但JS里函数本身也是对象,TS完全可以优雅地处理这种情况,不用反复依赖as类型断言。

第一步:定义函数+属性的交叉类型

首先,我们需要创建一个交叉类型,把函数的调用签名和它的额外属性合并在一起,完整描述wait的类型:

// 完整描述wait函数的类型:既是调用函数,又可选带有reject方法
type WaitFunction = ((ms: number) => Promise<void>) & {
  reject?: (reason: string) => void;
};

这里用&把两部分类型合并:前半部分是wait作为函数的调用签名,后半部分是它携带的可选reject属性的类型。

第二步:用类型声明变量并实现逻辑

接下来直接用这个类型声明wait变量,实现时只需要做一次类型断言(比你之前多次零散断言优雅得多),之后所有属性访问都会被TS正确推断:

const wait: WaitFunction = ((ms: number) => {
  return new Promise<void>((resolve, reject) => {
    const timeoutId = setTimeout(() => {
      // 直接访问wait.reject,TS能识别这个属性的存在
      delete wait.reject;
      resolve();
    }, ms);

    // 直接赋值reject属性,类型完全匹配,无需额外断言
    wait.reject = (reason: string) => {
      clearTimeout(timeoutId);
      reject(reason);
    };
  });
}) as WaitFunction;

第三步:复用类型处理多个类似函数

如果你的代码库中有大量这类“带额外属性的函数”,可以定义一个通用类型模板,避免重复编写相似类型:

// 通用模板:给任意返回Promise的函数添加reject属性
type FunctionWithReject<T extends (...args: any[]) => Promise<any>> = T & {
  reject?: (reason: string) => void;
};

// 比如另一个类似的sleep函数,直接复用模板
type SleepFunction = FunctionWithReject<(ms: number) => Promise<void>>;

const sleep: SleepFunction = ((ms: number) => {
  // 实现逻辑和wait类似...
  return new Promise(resolve => setTimeout(resolve, ms));
}) as SleepFunction;

这个方案的优势

  • 避免零散的as断言,类型定义集中清晰,可读性更强
  • 所有类型检查由TS自动完成,减少手动断言带来的潜在错误
  • 通用类型模板可以复用在多个类似函数上,符合代码复用原则

内容的提问来源于stack exchange,提问作者Cal Courtney

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 17:06:50