import Vue from 'vue'; import getOwnPropertyDescriptor = Reflect.getOwnPropertyDescriptor; export interface Decorator { decorate(f: (...farg: FArgs) => any, ...args: TArgs): (...farg: FArgs) => TRet; (...args: TArgs): (target, name: string | symbol, descriptor: TypedPropertyDescriptor<(...farg: FArgs) => FRet>) => void; } export function decorator (decorate: (f: (...farg: FArgs) => FRet, ...args: TArgs) => (...farg: FArgs) => TRet) : Decorator { const factory = function (this: Decorator, ...args: TArgs) { return (target, name: string | symbol, descriptor: PropertyDescriptor) => { descriptor.value = decorate(descriptor.value, ...args); } } as Decorator; factory.decorate = decorate; return factory; } export const throttle = decorator(function (decorated, time: number) { let timeout; return function (this: any, ...args) { if (typeof timeout === 'undefined') { timeout = window.setTimeout(() => { decorated.call(this, ...args); timeout = undefined; }, time); } } }); export const debounce = decorator(function (decorated, time: number, max: number = time * 3) { let timeout; return function (this: any, ...args) { if (typeof timeout !== 'undefined') { window.clearTimeout(timeout); } timeout = window.setTimeout(() => { timeout = undefined; decorated.call(this, ...args); }, time); } }); export const condition = decorator(function (decorated: (...args: Args) => Ret, predicate: (...args: Args) => boolean) { return function (this: any, ...args: Args) { if (predicate(...args)) { return decorated(...args); } } }); // decorators.js import { createDecorator } from 'vue-class-component' export const notify = (name?: string) => createDecorator((options, key) => { const symbol = Symbol(key); if (typeof options.computed === 'undefined') { options.computed = {}; } options.computed[key] = { get: function (this: Vue) { return this[symbol]; }, set: function (this: Vue, value: any) { this[symbol] = value; this.$emit(name ? name : `update:${key}`, value); } } });