MST

星途 面试题库

面试题:TypeScript装饰器常见陷阱之参数类型问题

在TypeScript装饰器中,当装饰一个方法时,若方法接收参数,可能会遇到参数类型相关的陷阱。请举例说明如何在装饰器中正确处理被装饰方法的参数类型,以及可能出现的错误情况,并给出解决办法。
31.2万 热度难度
前端开发TypeScript

知识考点

AI 面试

面试题答案

一键面试

1. 正确处理参数类型示例

假设我们有一个简单的类和一个装饰器来处理方法:

function logArgs(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;
    descriptor.value = function (...args: any[]) {
        console.log('Arguments:', args);
        return originalMethod.apply(this, args);
    };
    return descriptor;
}

class MyClass {
    @logArgs
    greet(name: string, age: number) {
        return `Hello, ${name}! You are ${age} years old.`;
    }
}

const myObj = new MyClass();
console.log(myObj.greet('Alice', 30));

在这个例子中,logArgs 装饰器使用了 ...args: any[] 来接收所有传入 greet 方法的参数,这样可以确保无论 greet 方法有多少个参数,装饰器都能正确处理。

2. 可能出现的错误情况

如果在装饰器中硬编码参数类型,就会出现问题。例如:

function wrongLogArgs(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;
    descriptor.value = function (name: string, age: number) {
        console.log('Arguments:', name, age);
        return originalMethod.apply(this, arguments);
    };
    return descriptor;
}

class AnotherClass {
    @wrongLogArgs
    greet(name: string, age: number) {
        return `Hello, ${name}! You are ${age} years old.`;
    }
}

const anotherObj = new AnotherClass();
// 假设这里我们想添加一个新的参数,比如问候语类型
// 如果使用硬编码的参数类型,就会报错
// anotherObj.greet('Bob', 25, 'Formal'); 

这里装饰器 wrongLogArgs 硬编码了参数类型为 stringnumber,如果后续被装饰的方法参数有变化,就会导致类型错误。

3. 解决办法

使用 ...args: any[] 来接收参数,这样可以灵活处理不同数量和类型的参数,就像第一个示例中的 logArgs 装饰器一样。另外,如果需要对参数进行类型检查,可以在装饰器内部使用类型断言或类型保护。例如:

function betterLogArgs(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;
    descriptor.value = function (...args: any[]) {
        if (args.length === 2 && typeof args[0] ==='string' && typeof args[1] === 'number') {
            console.log('Arguments:', args);
        } else {
            console.log('Unexpected argument types or count');
        }
        return originalMethod.apply(this, args);
    };
    return descriptor;
}

class YetAnotherClass {
    @betterLogArgs
    greet(name: string, age: number) {
        return `Hello, ${name}! You are ${age} years old.`;
    }
}

const yetAnotherObj = new YetAnotherClass();
console.log(yetAnotherObj.greet('Charlie', 22));

这样既可以灵活接收参数,又能在必要时进行类型检查。