【问题标题】:Typescript Universal method decorator returning Promise as valueTypescript Universal 方法装饰器返回 Promise 作为值
【发布时间】:2020-04-27 16:56:06
【问题描述】:

我正在尝试实现一个通用的方法装饰器,它可以与原型方法和实例方法一起使用。

基于:Typescript decorators not working with arrow functions

从下面的代码可以看出,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

【问题讨论】:

    标签: javascript node.js typescript typescript-typings


    【解决方案1】:

    async 函数将始终返回一个承诺。

    您已将patchedFn 定义为async 函数,您必须修改以将其声明为普通函数,或者在调用者处进行await(如果有此意图)。

    【讨论】:

      【解决方案2】:

      根据 Edward 上面的回答,我用下面的代码解决了这个问题。

      我已经在箭头函数、实例和静态方法上对其进行了测试。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-08-02
        • 2014-02-18
        • 2021-06-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多