MST

星途 面试题库

面试题:TypeScript深度反射场景优化

假设在一个大型TypeScript项目中,存在复杂的类继承体系和大量使用泛型的情况。现在需要实现一个通用的反射机制,能够准确获取任意类实例(包括继承类和使用泛型的类)的所有属性和方法,并且能处理属性和方法的访问修饰符(如`private`、`protected`),要求尽可能高效且具有扩展性,描述你的设计思路并给出关键代码示例。
34.2万 热度难度
前端开发TypeScript

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 使用 Reflect API:TypeScript 编译为 JavaScript 后,privateprotected 修饰符主要用于编译时检查,运行时并不存在。然而,可以通过 Reflect API 来获取对象的元数据,以模拟访问修饰符的处理。
  2. 递归处理继承体系:对于类继承体系,需要从子类开始,逐步向上遍历父类,以获取所有层次的属性和方法。
  3. 处理泛型:由于泛型在运行时会被擦除,对于使用泛型的类,主要关注其实例化后的实际类型的属性和方法。

关键代码示例

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);