首页 > 解决方案 > 这是不恰当使用泛型的案例吗?

问题描述

我试图弄清楚泛型的一种有趣用法的目的:

让我们以这个类为例:

class Person {
    constructor(public personName: string) { }

    setName(name: string) {
        this.personName = name
    }
}

这个装饰器:

export function logger<T extends any[]>(message: string | ((...msgArgs: T) => string)) {
    return (_target: object, _propertyKey: string, propDesc: PropertyDescriptor) => {
        const classMethod = propDesc.value;
        propDesc.value = function (...args: T) {
            const logMsg: string = typeof message === 'function' ? message.apply(this, args) : message;
            console.log(logMsg)
            const result = classMethod.call(this, ...args);

            return result;
        };

        return propDesc;
    };
}

我们可以这样使用它:

@logger("Setting name")
setName(name: string) {
        this.personName = name
    }

或者

@logger((nameParam)=> `Setting name ${nameParam}`)
setName(name: string) {
        this.personName = name
    }

按预期工作。但是我不明白为什么这应该是通用的:

logger<T extends any[]>

是的,它使我们能够使用T而不是any[]在多个地方使用。但看起来这只是一个棘手的解决方法和滥用通用语法。基本上这个泛型与泛型无关......甚至最糟糕的是装饰器propDesc.value = function和参数函数| ((...msgArgs: T) => string)共享相同的类型,即使它们没有任何共同之处。

我仍然觉得我在上面的陈述中可能是错误的。所以我想知道在这种特殊情况下是否有任何理由使用泛型来支持any[]type anyArg = any[]

ps 我有一种强烈的感觉,实现是受这篇文章的启发

标签: typescript

解决方案


在这种情况下T,仅用于键入rest运算符。

而且,你是对的,没有意义使用T extends any[],因为我们可以用下一种方式:

export function logger<T,>(message: string | ((...msgArgs: T[]) => string)) {
    return (_target: object, _propertyKey: string, propDesc: PropertyDescriptor) => {
        const classMethod = propDesc.value;
        propDesc.value = function (...args: T[]) {
            const logMsg: string = typeof message === 'function' ? message.apply(this, args) : message;
            console.log(logMsg)
            const result = classMethod.call(this, ...args);

            return result;
        };

        return propDesc;
    };
}

考虑下一个例子:

export function logger<T,>(message: string | ((...msgArgs: T[]) => string)) {

}

logger((...args: string[]) => 'bar')

操场

请将鼠标悬停在logger((...args: string[]) => 'bar')

您应该看到,T泛型被推断为 string :

function logger<string>(message: string | ((...msgArgs: string[]) => string)): void

等等,如果我摆脱这个泛型怎么办?


export function logger(message: string | ((...msgArgs: unknown[]) => string)) {

}


logger((...args:number[])=>'foo') // error

我不再能够输入args数组。


推荐阅读