TypeScript装饰器相关问题:能否作用于接口及如何让编译器识别其添加的属性类型
TypeScript装饰器相关问题:能否作用于接口及如何让编译器识别其添加的属性类型
当然可以搞定这个问题!要让TypeScript编译器认出装饰器自动添加的_x、_y这类属性,还能正确推断它们的类型,咱们可以从类型扩展和装饰器的类型声明入手,下面给你具体拆解:
第一步:先定义一个泛型类型,描述被装饰后类的属性结构
这个类型会自动把原类的属性映射成下划线开头的版本,类型和原属性完全一致,相当于提前给TS“打预防针”:这个类会多出这些属性哦!type ClassWithUnderscoreProps<T> = T & { [K in keyof T as `_${string & K}`]: T[K]; };第二步:给装饰器补上类型声明和运行时逻辑
咱们要让装饰器不仅能在代码运行时给类加上属性,还要在编译时把类型信息同步给TS。这里用asserts语法做类型断言,明确告诉TS:经过这个装饰器处理的类,会拥有那些下划线开头的属性:// 装饰器的运行时逻辑:给类实例添加下划线属性的访问器 function addUnderscore(target: any, propertyKey: string | symbol) { const underscoreKey = `_${String(propertyKey)}`; Object.defineProperty(target, underscoreKey, { get() { return this[propertyKey]; }, set(value) { this[propertyKey] = value; }, enumerable: true, configurable: true }); } // 给装饰器加类型声明,让TS识别扩展后的属性 declare function addUnderscore<T>( target: any, propertyKey: keyof T ): asserts target is ClassWithUnderscoreProps<T>;第三步:在类里用装饰器,TS就能自动识别属性啦
现在你再用Foo类的实例,TS不仅不会报错,还能正确给出_x、_y的类型提示,赋值时也会做类型检查:class Foo { @addUnderscore x = 1; @addUnderscore y = 2; } const foo = new Foo(); console.log(foo._x); // TS清楚知道这是number类型,完美识别! foo._y = 100; // 赋值也会严格校验类型,超省心
如果你的类属性不多,也可以用更直接的接口合并方式:先定义类,再写一个同名接口,手动声明装饰器添加的属性和类型,TS同样能立刻识别:
class Foo { @addUnderscore x = 1; @addUnderscore y = 2; } // 接口合并,手动告诉TS Foo类还有这些属性 interface Foo { _x: number; _y: number; }
简单来说,核心就是通过类型扩展或者接口合并,把装饰器动态添加的属性“同步”给TypeScript编译器,这样它就能准确识别这些属性的存在和类型啦!
备注:内容来源于stack exchange,提问作者user29889977
相关产品推荐
相关产品推荐

