You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

带泛型参数的类装饰器实现:参数关联类类型与构造子类化

我来帮你实现这个带类型关联参数的类装饰器,同时满足子类化构造函数并访问选项的需求。咱们一步步来:

实现带类型关联参数的类装饰器

首先先完善类型定义,确保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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 04:19:43