TypeScript装饰器包装类如何访问原类静态成员?
解决TypeScript装饰器中访问原类静态成员的类型错误
这个问题我之前也碰到过——核心是TypeScript的类型系统没自动识别到你通过Object.assign复制过去的静态成员,再加上装饰器的类型定义没跟上运行时的操作。下面给你两种针对性的解决思路,按需选择:
情况1:Wrapper需要继承原类的实例成员
如果你的装饰器只是想增强原类的功能(比如重写方法、添加新逻辑),可以让Wrapper直接继承原类,同时通过泛型让TypeScript识别静态成员:
function decorator<T extends { new(...args: any[]): any }>(opts?: any) { return function (Class: T) { // 让Wrapper继承原类,保留实例成员 class Wrapper extends Class { // 这里添加你的装饰器逻辑,比如重写方法 someNewMethod() { return "enhanced"; } } // 运行时复制原类的静态成员到Wrapper Object.assign(Wrapper, Class); // 断言返回类型为原类构造函数类型,让TS识别静态成员 return Wrapper as T; }; } class SmthImpl { static readonly staticConst = 7; instanceProp = 42; } const Smth = decorator()(SmthImpl); // 现在访问静态成员不会报错 console.log(Smth.staticConst); // 7 // 实例同时拥有原类和Wrapper的成员 const instance = new Smth(); console.log(instance.instanceProp); // 42 console.log(instance.someNewMethod()); // "enhanced"
情况2:Wrapper是完全独立的类(不需要继承原类实例)
如果你的Wrapper是全新的类,只是需要复用原类的静态成员,可以通过交叉类型让TypeScript同时识别Wrapper的构造函数和原类的静态成员:
function decorator<T extends { new(...args: any[]): any }>(opts?: any) { return function (Class: T) { class Wrapper { // 自定义Wrapper的实例逻辑 constructor() { this.OriginalInstance = new Class(); } OriginalInstance: InstanceType<T>; wrapperMethod() { return "wrapper logic"; } } // 运行时复制原类静态成员 Object.assign(Wrapper, Class); // 返回交叉类型:Wrapper构造函数 + 原类构造函数的静态成员 return Wrapper as typeof Wrapper & T; }; } class SmthImpl { static readonly staticConst = 7; instanceMethod() { return "original method"; } } const Smth = decorator()(SmthImpl); // 静态成员正常访问 console.log(Smth.staticConst); // 7 // 实例使用Wrapper的自定义逻辑 const instance = new Smth(); console.log(instance.wrapperMethod()); // "wrapper logic" console.log(instance.OriginalInstance.instanceMethod()); // "original method"
为什么原来的方法不行?
你之前用Object.assign(Smth, SmthImpl)是正确的运行时操作,但TypeScript的类型推断是基于变量声明时的类型(也就是typeof Wrapper),它不会自动因为你后续的Object.assign更新变量类型。所以必须通过泛型捕获原类类型 + 类型断言/交叉类型,让TypeScript知道返回的构造函数包含原类的静态成员。
内容的提问来源于stack exchange,提问作者Qwertiy
相关产品推荐
相关产品推荐

