MST

星途 面试题库

面试题:TypeScript 装饰器与依赖注入

假设你正在开发一个前端应用,需要使用依赖注入模式,结合 TypeScript 装饰器来实现一个简单的服务注入功能,描述实现思路并给出关键代码示例。
17.3万 热度难度
前端开发TypeScript

知识考点

AI 面试

面试题答案

一键面试

实现思路

  1. 定义装饰器:使用 TypeScript 装饰器来标记需要注入的服务类和注入点。
  2. 创建服务容器:用于存储和管理服务实例。
  3. 解析依赖关系:在实例化组件或服务时,根据装饰器标记从服务容器中获取依赖的实例并注入。

关键代码示例

  1. 定义装饰器
// 用于标记服务类的装饰器
function Injectable() {
    return function (target: Function) {
        Reflect.defineMetadata('isInjectable', true, target);
    };
}

// 用于标记注入点的装饰器
function Inject() {
    return function (target: any, propertyKey: string) {
        const type = Reflect.getMetadata('design:type', target, propertyKey);
        Reflect.defineMetadata('injectProperty', type, target, propertyKey);
    };
}
  1. 创建服务容器
class ServiceContainer {
    private services: Map<Function, any> = new Map();

    register<T>(service: new () => T): void {
        if (Reflect.getMetadata('isInjectable', service)) {
            this.services.set(service, new service());
        } else {
            throw new Error('The service is not injectable');
        }
    }

    get<T>(service: new () => T): T {
        return this.services.get(service) as T;
    }
}
  1. 使用示例
// 定义一个可注入的服务
@Injectable()
class LoggerService {
    log(message: string) {
        console.log(`[LOG] ${message}`);
    }
}

// 定义一个依赖 LoggerService 的组件
class AppComponent {
    @Inject()
    private logger: LoggerService;

    constructor() {
        // 这里会在后续依赖注入时填充 logger
    }

    doSomething() {
        this.logger.log('Doing something...');
    }
}

// 使用服务容器
const container = new ServiceContainer();
container.register(LoggerService);
const appComponent = new AppComponent();

// 手动解析依赖并注入
const injectProperties = Object.getOwnPropertyNames(Object.getPrototypeOf(appComponent)).filter(key => 
    Reflect.getMetadata('injectProperty', appComponent, key)
);
injectProperties.forEach(key => {
    const type = Reflect.getMetadata('injectProperty', appComponent, key);
    appComponent[key] = container.get(type);
});

appComponent.doSomething();