MST

星途 面试题库

面试题:TypeScript静态类型检查下的装饰器与类型元编程问题

使用TypeScript的装饰器和类型元编程,实现一个可复用的日志记录装饰器。这个装饰器要能记录函数的调用参数和返回值,并且在静态类型检查时,对于被装饰函数的类型定义不能丢失或出现错误。同时,要考虑如何在复杂的类继承结构和模块导入导出场景下,保证装饰器对静态类型检查的兼容性和正确性,给出详细的设计思路和代码示例。
32.3万 热度难度
前端开发TypeScript

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 定义装饰器函数:使用 TypeScript 的装饰器语法,定义一个函数作为装饰器,它接收一个目标对象(可以是类的原型或者函数本身)、属性名以及属性描述符。
  2. 记录调用参数和返回值:在装饰器函数内部,创建一个新的函数来包裹原函数,在新函数中记录参数和返回值,并调用原函数。
  3. 保持类型定义:通过泛型来保证被装饰函数的类型定义在静态类型检查时不丢失或出错。
  4. 处理类继承结构和模块导入导出:确保装饰器在不同的类继承和模块场景下都能正常工作,特别是在类型检查时。这需要正确地处理类型声明和导入导出。

代码示例

// 定义日志记录装饰器
function log(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;
    descriptor.value = function(...args: any[]) {
        console.log(`Calling method ${propertyKey} with arguments:`, args);
        const result = originalMethod.apply(this, args);
        console.log(`Method ${propertyKey} returned:`, result);
        return result;
    };
    return descriptor;
}

// 示例类
class ExampleClass {
    @log
    public exampleMethod(a: number, b: string): boolean {
        return a > 0 && b.length > 0;
    }
}

// 测试示例
const example = new ExampleClass();
example.exampleMethod(1, 'test');

处理复杂类继承结构和模块导入导出

假设我们有一个继承结构:

// 基类
class BaseClass {
    @log
    public baseMethod(): string {
        return 'Base method result';
    }
}

// 子类
class SubClass extends BaseClass {
    @log
    public subMethod(): string {
        return super.baseMethod() +'from sub method';
    }
}

// 模块导入导出示例
// file1.ts
export class AnotherClass {
    @log
    public anotherMethod(): number {
        return 42;
    }
}

// file2.ts
import { AnotherClass } from './file1';
const another = new AnotherClass();
another.anotherMethod();

这样,通过上述方式,在不同的类继承结构和模块导入导出场景下,日志记录装饰器都能保持对静态类型检查的兼容性和正确性。