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

TypeScript如何以类型安全的方式为类添加属性(monkey patch)

TypeScript 类 Monkey Patch 类型安全实现方案

问题本质

类装饰器在运行时会修改类原型挂载属性,但TypeScript类型系统默认不会感知装饰器对类结构的修改,因此会抛出「目标类型上不存在对应属性」的编译错误。

实现方案

方案1:类内补充属性类型声明(最简单)

不需要修改装饰器逻辑,直接在被装饰的类内部用declare关键字声明新增属性的类型即可,不会生成额外运行时代码,仅做类型补充:

function extended(target: any) {
  const newProperty: string = 'hello';
  target.prototype.newProperty = newProperty;
}

@extended
class Test {
  // 仅做类型声明,无运行时逻辑
  declare newProperty: string;
}

const test = new Test();
// 类型推导正常,无编译错误
console.log(test.newProperty);

方案2:类型安全的装饰器封装(无需每个类手动声明)

给装饰器补充正确的类型定义,让其返回合并了新增属性的类构造函数类型,不需要在每个被装饰类里重复写声明:

// 定义新增属性的类型结构
type ExtendedInstance = {
  newProperty: string;
};

function extended<T extends new (...args: any[]) => object>(target: T) {
  const newProperty: string = 'hello';
  target.prototype.newProperty = newProperty;
  // 将返回的构造函数类型断言为合并了新增属性的类型
  return target as T & new (...args: ConstructorParameters<T>) => InstanceType<T> & ExtendedInstance;
}

// 直接用函数包裹类定义即可获得完整类型,不需要依赖实验性装饰器配置
const Test = extended(class Test {
  // 类原有业务逻辑
});

const test = new Test();
// 自动推导newProperty为string类型,无编译错误
console.log(test.newProperty);

注意:TypeScript 5.0+ 启用的标准TC39装饰器不支持装饰器直接修改被装饰目标的类型,如果要使用@extended装饰器语法糖实现自动类型推导,需要在tsconfig中开启experimentalDecorators编译选项,使用旧版实验性装饰器实现。

不推荐方案:全局类型合并

如果要给所有对象批量挂载属性,可以通过全局接口合并给Object补充类型,但这种方式会污染全局类型定义,导致所有对象实例都被推导存在该属性,容易引发类型误判:

declare global {
  interface Object {
    newProperty: string;
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 15:21:19