您可以使用 TypeScript 装饰器将属性添加到方法调用吗?

Can you use TypeScript decorators to add properties to a method call?

现在在使用装饰器时 javascript 似乎可以工作(强制编译和方法可用),但是类型太严格了。

如您所见here以下内容无法编译:

declare var _: any;
export function Throttle(milli: number) {
    interface Throttled extends Function {
            now: Function
    }
    return function<T extends Throttled>(target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<Function>): TypedPropertyDescriptor<T> {
            let originalMethod = descriptor.value;
            // NOTE: Do not use arrow syntax here. Use a function expression in
            // order to use the correct value of `this` in this method
            descriptor.value = <any>_.throttle(function() {
                originalMethod.apply(this, arguments);
            }, milli);
            (<Throttled>descriptor.value).now = <any>function() {
                originalMethod.apply(this, arguments);
            };
            return <TypedPropertyDescriptor<T>>descriptor;
        }
}

class Ctrl {

    constructor(scope: any) { 
        scope.$watch("foo", this.throttledByClassWatch);
        this.throttledByClassWatch.now() //unrecommended now call
    }
    @Throttle(100000)
    private throttledByClassWatch() {
    }
}

我的类型可能有点不对,但我已经尝试了许多其他排列。好像是因为期望的类型是

declare type MethodDecorator = <T>(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<T>) => TypedPropertyDescriptor<T> | void; 

因此输入 T 必须与输出 T 匹配。

理想情况下,now 也可以继承通用类型 T,因此可以对其进行类型检查。

TypeScript 的类型系统无法描述方法的属性。

你可以做的是这些方面的事情:

interface Throttled extends Function {
    now: Function;
}

function Throttle(milli: number) {
    return function(target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<any>) {
        let originalMethod = descriptor.value;

        descriptor.value = _.throttle(function() {
            originalMethod.apply(this, arguments);
        }, milli);

        (<Throttled>descriptor.value).now = function() {
            originalMethod.apply(this, arguments);
        };

        return descriptor;
    };
}

class Ctrl {
    constructor(scope: any) {
        this.runNow(this.throttledByClassWatch);
    }

    @Throttle(100000)
    private throttledByClassWatch() {
    }

    private runNow(method: Function, ...args: any[]) {
        (method as Throttled).now.apply(this, args);
    }
}

基本上,有一个可重用的函数,可以抽象出对受限方法的调用 .now()