MST

星途 面试题库

面试题:TypeScript 装饰器与元数据反射机制在复杂业务场景中的应用

假设你正在开发一个基于 TypeScript 的 Web 框架,需要利用装饰器和元数据反射机制实现路由功能。要求能够通过装饰器将类的方法与特定的 URL 路径绑定,并且可以在运行时根据请求的 URL 动态调用对应的方法。请描述实现思路并给出关键代码示例。
20.1万 热度难度
前端开发TypeScript

知识考点

AI 面试

面试题答案

一键面试

实现思路

  1. 引入必要的库:在 TypeScript 中使用装饰器和元数据反射,需要引入 reflect - metadata 库,并在 tsconfig.json 中配置 experimentalDecoratorsemitDecoratorMetadatatrue
  2. 定义路由装饰器:创建一个装饰器函数,用于将类的方法与特定的 URL 路径绑定,并将这些信息存储到元数据中。
  3. 创建路由映射:在运行时,通过反射机制读取元数据,构建一个路由映射表,将 URL 路径与对应的类实例方法关联起来。
  4. 处理请求:当接收到 HTTP 请求时,根据请求的 URL 在路由映射表中查找对应的方法,并调用该方法处理请求。

关键代码示例

  1. 安装依赖
    npm install reflect - metadata
    
  2. 配置 tsconfig.json
    {
        "compilerOptions": {
            "experimentalDecorators": true,
            "emitDecoratorMetadata": true
        }
    }
    
  3. 定义路由装饰器和路由映射
    import 'reflect - metadata';
    
    const ROUTES_METADATA = 'routes';
    
    // 路由装饰器
    function Route(path: string) {
        return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
            let routes = Reflect.getMetadata(ROUTES_METADATA, target) || [];
            routes.push({ path, propertyKey });
            Reflect.defineMetadata(ROUTES_METADATA, routes, target);
        };
    }
    
    // 构建路由映射
    function buildRouteMap(target: any) {
        const routes = Reflect.getMetadata(ROUTES_METADATA, target) || [];
        const instance = new target();
        return routes.reduce((acc, route) => {
            acc[route.path] = instance[route.propertyKey].bind(instance);
            return acc;
        }, {} as { [key: string]: Function });
    }
    
  4. 使用示例
    class MyController {
        @Route('/home')
        home() {
            return 'This is the home page';
        }
    
        @Route('/about')
        about() {
            return 'This is the about page';
        }
    }
    
    const routeMap = buildRouteMap(MyController);
    
    // 模拟处理请求
    function handleRequest(url: string) {
        const handler = routeMap[url];
        if (handler) {
            return handler();
        }
        return '404 Not Found';
    }
    
    console.log(handleRequest('/home'));
    console.log(handleRequest('/about'));
    console.log(handleRequest('/unknown'));