简体   繁体   English

打字稿通用方法装饰器返回 Promise 作为值

[英]Typescript Universal method decorator returning Promise as value

I'm trying to implement a universal method decorator that can be used with both prototype and instance methods.我正在尝试实现一个可以与原型和实例方法一起使用的通用方法装饰器。

Based off: Typescript decorators not working with arrow functions基于: Typescript 装饰器不适用于箭头函数

As you can see from the code below, instanceMethod() is returning a Promise.从下面的代码中可以看出, instanceMethod() 正在返回一个 Promise。

Is there a way I can return the correct value?有没有办法可以返回正确的值?

Decorator code:装饰器代码:

export function trace(verbose: boolean = false) {

    return (target: any, prop: string, descriptor?: TypedPropertyDescriptor<any>): any => {
        let fn
        let patchedFn

        if (descriptor) {
            fn = descriptor.value
        }

        return {
            configurable: true,
            enumerable: false,
            get() {
                if (!patchedFn) {
                    patchedFn = async (...args) => {
                        const ret = fn.call(this, ...args)
                        console.log(`typeof ret: ${typeof ret}`)
                        console.log(`return value: ${ret}`)
                        return ret
                    }
                }
                console.log(`get() patchedFn: ${patchedFn}`)
                return patchedFn
            },
            set(newFn) {
                console.log(`set() newFn: ${newFn}`)
                patchedFn = undefined
                fn = newFn
            },
        }

    }
}

Test class & test code:测试类和测试代码:

class Greeter {

    @trace()
    public instanceMethod(s: string): string {
        return s
    }

    @trace()
    public async instanceAsyncMethod(s: string): Promise<string> {
        return s
    }

    @trace()
    public instanceArrowMethod = (s: string): string => {
        return s
    }

}

async function test() {
    const greeter = new Greeter()
    const result1 = greeter.instanceMethod('1')
    console.log(`* instanceMethod: ${result1}`) // should return '1', instead returns a Promise
    const result2 = await greeter.instanceAsyncMethod('2')
    console.log(`* instanceAsyncMethod: ${result2}`)
    const result3 = await greeter.instanceArrowMethod('3')
    console.log(`* instanceArrowMethod: ${result3}`)

}

test()

Output:输出:

set() newFn: (s) => {
            return s;
        }
get() patchedFn: (...args) => __awaiter(this, void 0, void 0, function* () {
                        console.log(`typeof fn: ${typeof fn}`);
                        const ret = fn.call(this, ...args);
                        console.log(`typeof ret: ${typeof ret}`);
                        console.log(`return value: ${ret}`);
                        return ret;
                    })
typeof ret: string
return value: 1
* instanceMethod: [object Promise] <<<<<<<<<< The instance method is returning a Promise
get() patchedFn: (...args) => __awaiter(this, void 0, void 0, function* () {
                        console.log(`typeof fn: ${typeof fn}`);
                        const ret = fn.call(this, ...args);
                        console.log(`typeof ret: ${typeof ret}`);
                        console.log(`return value: ${ret}`);
                        return ret;
                    })
typeof ret: object
return value: [object Promise]
* instanceAsyncMethod: 2
get() patchedFn: (...args) => __awaiter(this, void 0, void 0, function* () {
                        console.log(`typeof fn: ${typeof fn}`);
                        const ret = fn.call(this, ...args);
                        console.log(`typeof ret: ${typeof ret}`);
                        console.log(`return value: ${ret}`);
                        return ret;
                    })
typeof ret: string
return value: 3
* instanceArrowMethod: 3

An async function will always return a promise. async函数将始终返回一个承诺。

You have patchedFn defined as an async function, you will either have to modify to declare it as normal function, or await at the caller if it is intended.您已将patchedFn定义为async函数,您必须进行修改以将其声明为普通函数,或者如果有意在调用者处await

Based on Edward's answer above, I fixed the issue with the following code.根据上面爱德华的回答,我用以下代码解决了这个问题。

I've tested it on arrow function, instance and static methods.我已经在箭头函数、实例和静态方法上对其进行了测试。

export function trace(verbose: boolean = false) {

    return (target: any, prop: string, descriptor?: TypedPropertyDescriptor<any>): any => {
        let fn
        let patchedFn

        if (target instanceof Function) {
            // for static methods return function itself
            return target
        }

        if (descriptor) {
            fn = descriptor.value
        }

        return {
            configurable: true,
            enumerable: false,
            get() {
                if (!patchedFn) {
                    patchedFn = (...args) => {
                        const ret = fn.apply(this, args)
                        if (ret instanceof Promise) {
                            // execute the promise
                            ret.then((data) => {
                                return data
                            }).catch((error) => {
                                console.log(error)
                            })
                        }
                        return ret
                    }
                }
                return patchedFn
            },
            set(newFn) {
                patchedFn = undefined
                fn = newFn
            },
        }

    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM