打字稿方法返回未定义的方法装饰器

Posted

技术标签:

【中文标题】打字稿方法返回未定义的方法装饰器【英文标题】:Typescript method is return undefined with method decorator 【发布时间】:2016-11-11 18:59:36 【问题描述】:

如果这是一个愚蠢的问题,我深表歉意。我是打字稿和学习打字稿装饰器的新手。我找到了一个代码:MethodDecorator 来记录参数和结果。

日志装饰器

function log (target: Object, key: string, descriptor: TypedPropertyDescriptor<any>) 
    let originalMethod = descriptor.value;
    descriptor.value = function (...args:any[]) 
        //before
        console.log(`$key method called with args: $JSON.stringify(args)`);

        let result = originalMethod.apply(this, args);

        //after
        console.log(`$key method return value: $JSON.stringify(result)`);
    
    return descriptor;

我在 Book 类中使用带有 setId 和 getId 方法的 @log

book.ts

class Book
    constructor(public id: number, public title: string, public publisher: string)

    @log
    setId(id: number)
        this.id = id;
    
    @log
    getId(): number
        return this.id;
    

所有代码都可以正常工作,但是当我运行此代码时 getId 返回 undefined。

let book = new Book(1, "Learn TypeScript", "O\'Reilly Media");

let favBookId = book.getId();
console.log("Book before setId: ");
console.log(book);
console.log("Favourite book id: "+favBookId);

book.setId(5);
console.log("Book after setId: ");
console.log(book);
console.log("Favourite book id: "+favBookId);

我的 tsconfig.json


    "compilerOptions": 
        "target": "es5",
        "module": "commonjs",
        "removeComments": false,
        "experimentalDecorators": true
    

编译运行:

tsc -p ./
node book.js

输出:

getId method called with args: []
getId method return value: 1
Book before setId:
Book id: 1, title: 'Learn TypeScript', publisher: 'O\'Reilly Media' 
Favourite book id: undefined
setId method called with args: [5]
setId method return value: undefined
Book after setId:
Book id: 5, title: 'Learn TypeScript', publisher: 'O\'Reilly Media' 
Favourite book id: undefined

我无法理解为什么 setId 可以按我的意愿工作而 getId 不能??

tsc -v: Version 1.8.10

【问题讨论】:

我也有同样的问题。你找到答案了吗? 【参考方案1】:

我不知道为什么互联网上的所有帖子都引用了此类示例,但我自己的方法装饰器上下文与 originalMethod.apply(this, args); 相关的问题

这确实根本不起作用(我不知道它是 ts 错误还是什么)。

在试错后,我发现以下解决方案有效,允许您在基类中拥有正确的上下文:

function myDecorator(target: Object, key: string, descriptor: TypedPropertyDescriptor<any>) 

        descriptor.value = function (...args:any[]) 
            // whatever code suits you here...
            // dont use "this", use "target"
            let result = originalMethod.apply(target, args);

        
        return descriptor;

现在你可以这样做:

export class Yeah 
    @myDecorator()
    helloWord() 
        let n = 5;
        return this.multiply(n);
    

    multiply(a: number) 
       return a * 2;
    


干杯

【讨论】:

将目标作为参数传递将提供类 Prototype 而不是实际实例。使用this 可能是大多数人想要的,但请务必使用实际函数而不是箭头函数。【参考方案2】:

我的天啊,我以为你的问题和我一样,但事实并非如此。

问题只是由you return nothing重新定义函数引起的。

这是您的原始代码块:

descriptor.value = function (...args:any[]) 
        //before
        console.log(`$key method called with args: $JSON.stringify(args)`);

        let result = originalMethod.apply(this, args);

        //after
        console.log(`$key method return value: $JSON.stringify(result)`);
    

现在,返回它,它会正常工作。

descriptor.value = function (...args:any[]) 
        //...
        let result = originalMethod.apply(this, args);
        //...
        return result; //ADD HERE!!!
    

【讨论】:

【参考方案3】:

这是一个完整的工作示例:

function log(msg: string): MethodDecorator 
  return (
    target: Object,
    key: string | symbol,
    descriptor: PropertyDescriptor
  ) => 
    let originalMethod = descriptor.value;
    descriptor.value = function (...args: any[]) 
      //before
      if (args.length >0)  console.log(`$msg $key.toString() method called with args: $JSON.stringify(args)`);
      let result = originalMethod!.apply(this, args);
      //after
      if (result) console.log(`$key.toString() method return value: $JSON.stringify(result)`);
    ;
    return descriptor;
  ;


class Book 
  constructor(
    public id: number,
    public title: string,
    public publisher: string
  ) 

  @log('setting ')
  setId(id: number) 
    this.id = id;
  
  @log('getting ')
  getId(): number 
    return this.id;
  


const a = new Book(1, "title", "publisher");
a.setId(2);
a.getId();

你可以在typescript playground运行它

【讨论】:

以上是关于打字稿方法返回未定义的方法装饰器的主要内容,如果未能解决你的问题,请参考以下文章

Vue Prop 未定义,和/或不能在 v-for 上使用。使用打字稿和装饰器

带有猫鼬的打字稿:无法读取未定义的属性“CasterConstructor”

如何根据输入为字符串或未定义来创建返回字符串或未定义的打字稿函数?

Angular2 装饰器未定义

打字稿自定义装饰器:this的上下文

打字稿 - 未捕获的 ReferenceError:未定义导出