设计思路
- 使用
Reflect
API:TypeScript 编译为 JavaScript 后,private
和 protected
修饰符主要用于编译时检查,运行时并不存在。然而,可以通过 Reflect
API 来获取对象的元数据,以模拟访问修饰符的处理。
- 递归处理继承体系:对于类继承体系,需要从子类开始,逐步向上遍历父类,以获取所有层次的属性和方法。
- 处理泛型:由于泛型在运行时会被擦除,对于使用泛型的类,主要关注其实例化后的实际类型的属性和方法。
关键代码示例
class ReflectUtil {
static getOwnPropertiesAndMethods(target: any) {
const properties: { [key: string]: { value: any; accessModifier: string } } = {};
const methods: { [key: string]: { value: any; accessModifier: string } } = {};
const ownKeys = Reflect.ownKeys(target);
ownKeys.forEach(key => {
const desc = Reflect.getOwnPropertyDescriptor(target, key);
if (desc) {
if (typeof desc.value === 'function') {
methods[key as string] = { value: desc.value, accessModifier: this.getAccessModifier(target, key as string) };
} else {
properties[key as string] = { value: desc.value, accessModifier: this.getAccessModifier(target, key as string) };
}
}
});
return { properties, methods };
}
static getAccessModifier(target: any, propertyKey: string): string {
// 这里简单模拟,实际可基于元数据实现更精确判断
if (propertyKey.startsWith('_')) {
return 'private';
} else if (propertyKey.startsWith('$')) {
return 'protected';
}
return 'public';
}
static getAllPropertiesAndMethods(target: any) {
let current = target;
const allProperties: { [key: string]: { value: any; accessModifier: string } } = {};
const allMethods: { [key: string]: { value: any; accessModifier: string } } = {};
while (current) {
const { properties, methods } = this.getOwnPropertiesAndMethods(current);
Object.assign(allProperties, properties);
Object.assign(allMethods, methods);
current = Object.getPrototypeOf(current);
}
return { allProperties, allMethods };
}
}
// 示例使用
class Parent {
public publicProp = 'public';
protected _protectedProp = 'protected';
private __privateProp = 'private';
public publicMethod() {}
protected _protectedMethod() {}
private __privateMethod() {}
}
class Child extends Parent {
public childProp = 'child';
public childMethod() {}
}
const childInstance = new Child();
const { allProperties, allMethods } = ReflectUtil.getAllPropertiesAndMethods(childInstance);
console.log('All properties:', allProperties);
console.log('All methods:', allMethods);