簡體   English   中英

打字稿通用方法裝飾器返回 Promise 作為值

[英]Typescript Universal method decorator returning Promise as value

我正在嘗試實現一個可以與原型和實例方法一起使用的通用方法裝飾器。

基於: Typescript 裝飾器不適用於箭頭函數

從下面的代碼中可以看出, instanceMethod() 正在返回一個 Promise。

有沒有辦法可以返回正確的值?

裝飾器代碼:

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
            },
        }

    }
}

測試類和測試代碼:

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()

輸出:

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

async函數將始終返回一個承諾。

您已將patchedFn定義為async函數,您必須進行修改以將其聲明為普通函數,或者如果有意在調用者處await

根據上面愛德華的回答,我用以下代碼解決了這個問題。

我已經在箭頭函數、實例和靜態方法上對其進行了測試。

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