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

TypeScript中能否通过反射实例化泛型类型的属性?

解决方案

需求可以实现,核心需要处理TypeScript泛型的运行时擦除问题:泛型T的类型信息仅存在于编译阶段,运行时无法直接获取T的属性类型,因此需要手动标记需要实例化的类属性,补充运行时可读取的元数据即可。

实现思路

通过装饰器或者静态属性映射,提前标记需要实例化的嵌套类属性对应的构造函数,fromJSON方法遍历属性时读取提前标记的元数据,判断是否需要执行实例化操作。

代码实现(装饰器版本,推荐)

该方案语法更简洁,需要先在tsconfig.json中开启experimentalDecorators配置:

{
  "compilerOptions": {
    "experimentalDecorators": true
  }
}

1. 定义基础工具和抽象类

import 'reflect-metadata';

// 标记嵌套类属性的装饰器,传入对应类的构造函数
const Nested = (ctor: new (...args: any[]) => any) => {
  return (target: any, propertyKey: string) => {
    Reflect.defineMetadata('nested:constructor', ctor, target, propertyKey);
  };
};

// JSON入参的类型定义,支持嵌套结构
type JSONClassDictionary<T> = {
  [K in keyof T]?: T[K] extends object ? JSONClassDictionary<T[K]> | T[K] : T[K];
};

abstract class JSONClass<T> {
  constructor(json: JSONClassDictionary<T>) {
    this.fromJSON(json);
  }

  fromJSON(json: JSONClassDictionary<T>): void {
    for (const key in json) {
      if (!Object.prototype.hasOwnProperty.call(json, key)) continue;
      const jsonValue = json[key];
      // 读取当前属性标记的嵌套类构造函数
      const nestedCtor = Reflect.getMetadata('nested:constructor', this, key as string);
      
      if (nestedCtor && typeof jsonValue === 'object' && jsonValue !== null) {
        // 是嵌套类属性,执行实例化
        this[key as keyof this] = new nestedCtor(jsonValue) as this[keyof this];
      } else {
        // 原始类型直接赋值
        this[key as keyof this] = jsonValue as this[keyof this];
      }
    }
  }
}

2. 业务类使用示例

// 嵌套的PermissionGroup类,也继承JSONClass
class PermissionGroup extends JSONClass<PermissionGroup> {
  id: number;
  action: string;
}

class UserRole extends JSONClass<UserRole> {
  id: number;
  name: string;
  // 用@Nested标记该属性需要用PermissionGroup实例化
  @Nested(PermissionGroup)
  permissionGroup: PermissionGroup;
}

3. 调用示例

const role = new UserRole({
  id: 1,
  name: "Admin",
  permissionGroup: {
    id: 1,
    action: ".."
  }
});

// 验证实例化结果:permissionGroup已经是PermissionGroup的实例
console.log(role.permissionGroup instanceof PermissionGroup); // 输出 true

代码实现(无装饰器版本)

如果不想使用装饰器,可以用静态属性手动声明嵌套属性的构造函数映射:

type JSONClassDictionary<T> = {
  [K in keyof T]?: T[K] extends object ? JSONClassDictionary<T[K]> | T[K] : T[K];
};

abstract class JSONClass<T> {
  // 子类需要实现该静态属性,声明嵌套属性对应的构造函数
  static nestedProperties: Record<string, new (...args: any[]) => any> = {};

  constructor(json: JSONClassDictionary<T>) {
    this.fromJSON(json);
  }

  fromJSON(json: JSONClassDictionary<T>): void {
    const nestedCtors = (this.constructor as typeof JSONClass).nestedProperties;
    for (const key in json) {
      if (!Object.prototype.hasOwnProperty.call(json, key)) continue;
      const jsonValue = json[key];
      const nestedCtor = nestedCtors[key];
      
      if (nestedCtor && typeof jsonValue === 'object' && jsonValue !== null) {
        this[key as keyof this] = new nestedCtor(jsonValue) as this[keyof this];
      } else {
        this[key as keyof this] = jsonValue as this[keyof this];
      }
    }
  }
}

// 子类使用示例
class UserRole extends JSONClass<UserRole> {
  // 静态属性声明嵌套属性的构造函数
  static nestedProperties = {
    permissionGroup: PermissionGroup
  };
  id: number;
  name: string;
  permissionGroup: PermissionGroup;
}

问题解答

  1. 无法直接通过泛型T判断属性是否为类类型,因为泛型运行时会被擦除,所以需要通过上述手动标记的方式补充运行时可识别的元数据,即可区分原始类型属性和需要实例化的类属性。
  2. 标记后可以直接获取到属性对应的构造函数,传入JSON属性值执行new操作即可完成初始化,支持任意层级的嵌套类实例化,只要嵌套的类也继承JSONClass即可。

内容的提问来源于stack exchange,提问作者Constantin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 21:24:03