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

TypeScript中能否读取类定义属性?如何实现泛型遍历?

TypeScript中枚举类定义属性的方案

首先要明确:TypeScript的类型信息仅存在于编译阶段,运行时会被完全擦除,所以无法直接从泛型类型T中获取类的属性列表。你之前用Object.getOwnPropertyNames(new TestClass())没结果,是因为TestClass里只有类型声明,没有给属性赋值——这类属性不会被添加到实例对象中,自然无法被枚举。

下面是几种可行的替代方案:

1. 给类属性添加默认值

只要给属性赋初始值,实例化后这些属性就会存在于对象中,就能用Object.getOwnPropertyNames或Object.keys枚举:

class TestClass {
  public testProp: string = '';
  public testProp2: number = 0;
  public testProp3: boolean = false;
  public testProp4: Date = new Date();
  public testProp5: any = null;
}

function someMethod<T>(instance: T) {
  return Object.getOwnPropertyNames(instance);
}

// 调用后会输出所有属性名
console.log(someMethod(new TestClass()));

2. 使用装饰器收集属性

通过自定义装饰器标记类的属性,并利用Reflect API记录属性信息,这样即使属性没有初始值,也能在运行时拿到属性列表(需要在tsconfig.json中启用experimentalDecorators和emitDecoratorMetadata):

import 'reflect-metadata';

// 定义唯一标识用于存储属性列表
const PROPERTIES_KEY = Symbol('properties');

// 自定义装饰器,标记需要收集的属性
function TrackProperty() {
  return (target: any, propertyKey: string) => {
    const existingProps = Reflect.getMetadata(PROPERTIES_KEY, target) || [];
    existingProps.push(propertyKey);
    Reflect.defineMetadata(PROPERTIES_KEY, existingProps, target);
  };
}

class TestClass {
  @TrackProperty()
  public testProp: string;
  @TrackProperty()
  public testProp2: number;
  @TrackProperty()
  public testProp3: boolean;
  @TrackProperty()
  public testProp4: Date;
  @TrackProperty()
  public testProp5: any;
}

function someMethod<T>(cls: new () => T) {
  // 从类的原型中取出收集到的属性列表
  return Reflect.getMetadata(PROPERTIES_KEY, cls.prototype);
}

// 调用后输出所有标记的属性名
console.log(someMethod(TestClass));

3. 传递属性模板对象

如果可以接受传递一个包含目标类型所有属性的模板对象,就能直接枚举这个对象的属性,同时通过泛型推导获取类型:

function someMethod<T>(props: T) {
  return Object.keys(props) as Array<keyof T>;
}

// 传递包含所有属性的模板,自动推导类型
const propsList = someMethod({
  testProp: '',
  testProp2: 0,
  testProp3: false,
  testProp4: new Date(),
  testProp5: null
});
console.log(propsList);

关于构造带默认值的对象

TypeScript没有内置的辅助函数直接生成带默认值的类实例,但可以结合上面的装饰器方案实现一个工具函数,自动给标记的属性赋默认值:

function createDefaultInstance<T>(cls: new () => T): T {
  const instance = new cls();
  const properties = Reflect.getMetadata(PROPERTIES_KEY, cls.prototype) || [];

  properties.forEach((prop: string) => {
    // 根据属性类型的默认规则赋值
    switch (typeof instance[prop]) {
      case 'string':
        instance[prop] = '' as any;
        break;
      case 'number':
        instance[prop] = 0 as any;
        break;
      case 'boolean':
        instance[prop] = false as any;
        break;
      case 'object':
        // 特殊处理Date类型
        if (cls.prototype[prop] instanceof Date) {
          instance[prop] = new Date() as any;
        } else {
          instance[prop] = null as any;
        }
        break;
    }
  });

  return instance;
}

// 使用示例
const defaultInstance = createDefaultInstance(TestClass);
console.log(Object.getOwnPropertyNames(defaultInstance)); // 输出所有属性名

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 04:40:24