TypeScript中如何校验类是否带有指定装饰器并限制注册?
如何在注册类时校验是否存在指定装饰器?
完全可以实现这个需求,核心思路是给被装饰的类添加唯一标识,结合TypeScript类型系统做编译时校验,同时搭配运行时校验做兜底。下面是具体实现方案:
1. 改造装饰器,添加标识
修改Special装饰器,给被装饰的类构造函数添加一个独特的标记属性,同时通过TypeScript接口合并扩展构造函数类型,让类型系统能识别这个标记:
abstract class ExpectedBaseType { constructor(params: any) {} } type ExpectedBaseConstructor = { new (params: any): ExpectedBaseType; } // 扩展构造函数接口,声明装饰器标记的类型 interface ExpectedBaseConstructor { __isSpecialDecorated__?: boolean; } /** Special装饰器 */ function Special(value: string) { return function <T extends ExpectedBaseConstructor>(ctor: T) { console.log('@Special 已应用于', ctor.name); // 添加标记,标记该类已被装饰 ctor.__isSpecialDecorated__ = true; return ctor; } }
2. 定义仅接受装饰类的约束类型
创建一个专门的类型,只允许带有装饰器标记的类通过:
// 约束必须是ExpectedBaseType的子类,且带有@Special装饰器标记 type SpecialDecoratedConstructor = ExpectedBaseConstructor & { __isSpecialDecorated__: true; };
3. 修改注册表的注册方法
把register方法的参数类型改为上面定义的约束类型,这样TypeScript在编译阶段就会拦截未被装饰的类:
class Registry { register(special: SpecialDecoratedConstructor) { // 运行时兜底校验,防止通过类型断言绕过编译检查 if (!special.__isSpecialDecorated__) { throw new Error(`类 ${special.name} 未使用@Special装饰器,无法注册`); } console.log('已注册被@Special装饰的类:', special.name); } }
4. 测试效果
按照你的示例代码测试,就能得到预期的约束效果:
@Special('some-value') class ConcreteSpecialType extends ExpectedBaseType { constructor(params: any) { super(params); console.log('Created concrete special'); } } class ForgottenSpecialType extends ExpectedBaseType { constructor(params: any) { super(params); console.log('Created forgotten special'); } } const reg = new Registry(); // 编译、运行均正常 reg.register(ConcreteSpecialType); // 编译阶段直接报错:类型“typeof ForgottenSpecialType”缺少属性“__isSpecialDecorated__”,不符合约束要求 reg.register(ForgottenSpecialType);
补充说明
- 编译时校验能提前发现问题,避免运行时出错;
- 运行时校验是兜底方案,防止有人通过
as any等方式绕过类型检查; - 标记属性用双下划线开头,是为了避免和业务属性冲突,符合TS社区的约定。
内容的提问来源于stack exchange,提问作者Carsten Luxig
相关产品推荐
相关产品推荐

