带泛型参数的类装饰器实现:参数关联类类型与构造子类化
我来帮你实现这个带类型关联参数的类装饰器,同时满足子类化构造函数并访问选项的需求。咱们一步步来:
实现带类型关联参数的类装饰器
首先先完善类型定义,确保Options<T>和被装饰类的类型严格绑定,避免类型不匹配的问题:
// 定义选项类型,T是被装饰类的实例类型 type Options<T> = { accept: (instance: T) => boolean; // 你可以根据需求添加更多选项字段 }; // 定义装饰器的高阶类型,确保参数与目标类的类型严格匹配 type ClassDecoratorWithOptions<T> = (options: Options<T>) => (target: new () => T) => new () => T;
接下来实现装饰器函数deco,它会返回一个类装饰器,负责子类化原构造函数,并把选项传递给子类以便访问:
const deco: ClassDecoratorWithOptions<any> = <T>(options: Options<T>) => { return (target: new () => T) => { // 子类化原构造函数,保留原类的所有特性 class DecoratedClass extends target { // 把选项挂载为静态属性,方便子类直接访问 static readonly decoratorOptions: Options<T> = options; constructor() { super(); // 这里可以利用options做初始化逻辑,比如实例合法性校验 if (!options.accept(this as unknown as T)) { throw new Error("当前实例未通过装饰器的校验规则"); } } } return DecoratedClass; }; };
现在来测试使用示例,完全匹配你给出的代码结构,同时验证类型安全和子类访问选项的能力:
// 定义目标类 class MyClass { y: string; constructor() { this.y = "Hello"; } } // 创建选项,TypeScript会自动校验accept的参数类型是否匹配MyClass实例 const MyOptions: Options<MyClass> = { accept: function (instance: MyClass) { console.log("正在校验实例:", instance.y); return true; } }; // 使用装饰器装饰类 @deco(MyOptions) class DecoratedMyClass extends MyClass {} // 测试实例化 const instance = new DecoratedMyClass(); console.log(instance.y); // 输出 "Hello" // 子类直接访问装饰器选项 console.log(DecoratedMyClass.decoratorOptions.accept(instance)); // 输出 true
关键细节说明
- 类型安全保障:TypeScript会强制
Options<T>的accept方法参数必须是被装饰类的实例类型,如果你写错参数类型(比如写成string),编辑器会立刻报错,避免运行时问题。 - 子类化构造函数:装饰器返回的是原类的子类,完全保留原类的属性和方法,同时可以添加自定义逻辑(比如实例校验、初始化增强)。
- 选项访问方式:我们把选项挂载为子类的静态属性
decoratorOptions,这样子类本身或者它的派生类都能直接访问。如果需要在实例方法中使用选项,也可以在构造函数里把选项挂载到实例上(比如this.options = options,记得在原类中声明对应属性或用类型断言)。
扩展:支持带参数的构造函数
如果你的类构造函数需要接收参数,只需要稍微调整装饰器的类型和实现即可:
// 调整类型,支持任意构造函数参数 type ClassConstructor<T> = new (...args: any[]) => T; type ClassDecoratorWithOptions<T> = (options: Options<T>) => (target: ClassConstructor<T>) => ClassConstructor<T>; const deco: ClassDecoratorWithOptions<any> = <T>(options: Options<T>) => { return (target: ClassConstructor<T>) => { class DecoratedClass extends target { static readonly decoratorOptions: Options<T> = options; constructor(...args: any[]) { super(...args); if (!options.accept(this as T)) { throw new Error("当前实例未通过装饰器的校验规则"); } } } return DecoratedClass; }; }; // 测试带参数的类 class User { name: string; constructor(name: string) { this.name = name; } } const userOptions: Options<User> = { accept: (user) => user.name.length > 0 }; @deco(userOptions) class DecoratedUser extends User {} // 正常实例化 const validUser = new DecoratedUser("Alice"); // 会抛出错误,因为name为空 // const invalidUser = new DecoratedUser("");
这样就完美满足你的所有需求啦,既保证了类型安全,又实现了子类化构造函数和选项访问的能力。
内容的提问来源于stack exchange,提问作者MrVichr
相关产品推荐
相关产品推荐

