打字稿签名,用于高级装饰器功能

时间:2018-10-12 15:11:58

标签: typescript

是否可以为装饰器功能(我是指装饰器设计模式装饰器,而不是打字稿装饰器功能)编写类型签名?

我尝试过:

function decorate<T extends () => any>(callback: T): T {
    return (...args) => {
        console.log('called with args: ', args);
        return callback(...args);
    };
}

但是它给了我TS2322: Type '(...args: any[]) => any' is not assignable to type 'T'.

1 个答案:

答案 0 :(得分:0)

您可以在{3.0中使用Tuples in rest parameters and spread expressions

function decorate<A extends any[], R>(callback: (...a: A) => R): (...a: A) => R {
    return (...args) => {
        console.log('called with args: ', args);
        return callback(...args);
    };
}

function foo(s: number) {
    return s.toString();
}


function bar(s: number, o : string[]) {
    return s.toString();
}

var dBar = decorate(bar) // (s: number, o: string[]) => string
var dFoo = decorate(foo) // (s: number) => string

有一些注意事项,如评论中所指出。泛型不适用于这种方法。另外,上面的函数不能正确处理重载。有关过载问题的解决方法,请参见this answer

修改

一种版本,可以减少警告,但在实现中需要一些类型断言,该版本与您建议的版本很接近:

function decorate<T extends (...a: any[]) => any>(callback: T): T {
    return ((...args) => {
        console.log('called with args: ', args);
        return callback(...args);
    }) as any;
}

这可以更好地说明输入与输出相同,如果不需要对返回类型或参数进行其他类型的操作,则最好使用该输入。尽管此版本破坏了实现类型的安全性,但要获得完全的呼叫站点安全性,这是可以接受的折衷方案,因为它将与重载和泛型一起使用。