TypeScript 5.0新装饰器能否做类型检查?如何筛选带指定装饰器的类成员
问题
能否对TypeScript 5.0引入的新装饰器(非旧版装饰器)进行类型检查?目前初步认为不可行,但未找到相关答案。
示例代码如下:
装饰器实现:
function EntityOnly<C, ET>(_target: undefined, context: ClassFieldDecoratorContext<C, ET>) { // 在此处将字段注册到上下文元数据中 }
使用该装饰器的User类:
class User { id: number = 0; username: string = ''; @EntityOnly hashedPassword: any = {}; @EntityOnly IBAN: string = ''; }
已知可以通过以下方式筛选出User类中字符串类型成员的键联合类型:
type IfAny<T, Y, N> = 0 extends (1 & T)? Y : N; type StringMembers<T> = keyof { [P in keyof T as T[P] extends string? IfAny<T[P], never, P> : never]: any; }; // 类型为 "username" | "IBAN" let userStringMember: StringMembers<User>;
现提问:如何类似地声明由带有EntityOnly装饰器的成员键组成的联合类型?
解答
TypeScript类型系统本身无法直接感知运行时装饰器的应用——装饰器属于运行时特性,编译阶段的类型检查无法直接获取哪些字段被装饰器标记。但可以通过给装饰后的字段添加类型标记的方式,间接实现筛选目标字段的联合类型。
具体实现步骤
- 定义一个仅用于类型区分的独特标记,不影响运行时逻辑:
type EntityFieldMarker<T> = T & { __entityField?: never };
- 修改装饰器,让它返回的字段类型带上这个标记(运行时注册元数据的逻辑保持不变):
function EntityOnly<C, ET>(_target: undefined, context: ClassFieldDecoratorContext<C, ET>) { // 运行时元数据注册逻辑保留 return function(this: C, value: ET): EntityFieldMarker<ET> { return value as EntityFieldMarker<ET>; }; }
- 定义工具类型,筛选出带有该标记的字段键:
// 判断字段是否带有EntityFieldMarker类型标记 type IsEntityField<T> = T extends EntityFieldMarker<any>? true : false; // 生成带有EntityOnly装饰器的成员键联合类型 type EntityMembers<T> = keyof { [P in keyof T as IsEntityField<T[P]> extends true? P : never]: any; };
- 测试效果:
class User { id: number = 0; username: string = ''; @EntityOnly hashedPassword: any = {}; @EntityOnly IBAN: string = ''; } // 类型自动推导为 "hashedPassword" | "IBAN" let userEntityMember: EntityMembers<User>;
补充说明
如果不想修改字段的实际类型(避免类型标记影响日常类型使用),可以通过显式泛型参数手动指定装饰的字段,但这种方式缺乏自动化。上面的方案通过类型标记间接关联装饰器,是目前最便捷的自动化实现方式。
内容的提问来源于stack exchange,提问作者Wilco Bakker
相关产品推荐
相关产品推荐

