美文网首页
TypeScript: 类的装饰器(三)

TypeScript: 类的装饰器(三)

作者: Rollover | 来源:发表于2020-02-24 14:35 被阅读0次

带参数的类的装饰器

学习 python 的同学应该知道,python 中也有装饰器,而且 python 中的众多框架也在大量使用装饰器,如下就是 flask 的一个典型应用

from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello, World!"

python 的装饰器是可以接收参数的,那么 TypeScript 的类的装饰器该如何接收参数,我们需要在原来的装饰器函数上再套一层函数,由这层函数接收参数:

function addDecorator(isUse: boolean) {
  if (isUse) {
    return function(constructor: any) {
      console.log("use decorator");
    };
  } else {
    return function(constructor: any) {
      console.log("not use decorator");
    };
  }
}

@addDecorator(false)
class Test {}

很明显,当 addDecorator 传入 true 的时候会打印 use decorator,传入 false 的时候会打印 not use decorator

解决类装饰器函数参数为 any 的类型

回到类装饰器函数上:

function addDecorator(constructor: any) {
  constructor.prototype.getDecorator = () => {
    console.log("benjamin");
  };
}

@addDecorator
class Test {}

const t: Test = new Test();
t.getDecorator();

那这样写,会报如下错误:

原因之前也讲过了,那时我们的解决办法就是将t的类型临时改变一下:

(t as any).getDecorator();

这样就解决了报错,程序可以正确执行,但这不是一个很好的解决方案,我们可以采用 TypeScript 的泛型机制,把 any 改成泛型:

function addDecorator<T>(constructor: T) {
  constructor.prototype.getDecorator = () => {
    console.log("get decorator");
  };
}

这样修改,又会引来如下报错:


原因是T这个泛型没有js的构造函数,也就没有prototype这个原型属性,那么我们可以让泛型T继承构造函数,那泛型T就有了prototype这个原型属性

PS:构造函数 ,是一种特殊的方法。主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与 new 运算符一起使用在创建对象的语句中。

TypeScript 的构造函数写法如下:

new (...args: any[]) => any
或
new (...args: any[]) => {}

那么整体代码改为:

function addDecorator<T extends new (...args: any[]) => any>(constructor: T) {
  return class extends constructor {
    getDecorator() {
      console.log("get decorator");
    }
  };
}

@addDecorator
class Test {}

const t: Test = new Test();
(t as any).getDecorator();

来解释下这个构造函数,去掉 new,可以看出(...args: any[]) => any 就是一个函数,它接收多个类型为 any 的参数,返回类型为 any,再加上 new 就说明这是一个构造函数,那么可能有人会问,为什么构造函数要穿多个参数,我们可以把参数去掉,变为:

new () => {}

那么此时会得到一个报错:


通过报错提示,我们知道TypeScript的构造函数必须为一个接收多个参数为any类型的函数
那么改的另外一处代码为:

return class extends constructor {
  getDecorator() {
    console.log("get decorator");
  }
};

这段代码的意思是返回一个类,这个类继承了 constructor,它里面附加 getDecorator 方法,那么我们也可以在这个返回的类里边添加属性或修改属性值,代码修改如下:

function addDecorator<T extends new (...args: any[]) => {}>(constructor: T) {
  return class extends constructor {
    name = "decorator";
    getDecorator() {
      console.log("get decorator");
    }
  };
}

@addDecorator
class Test {
  private name: string;
  constructor(name: string) {
    console.log(name);
    this.name = name;
  }
}

const t: Test = new Test("test");
console.log(t);
(t as any).getDecorator();

我们在 Test 类中增添了一个构造函数,它接收一个 name 的参数,然后我们在装饰器中修改了 name 的属性,运行下代码:


但我们依然还是没有解决any类型问题


那么原因是在于我们的t实例在创建的时候,它本身并没有getDecorator这个方法,它是装饰器偷偷装饰上去的,而TypeScript推断不出来,我们就需要修改一下写法:

function addDecorator() {
  return function<T extends new (...args: any[]) => {}>(constructor: T) {
    return class extends constructor {
      name = "decorator";
      getDecorator() {
        console.log("get decorator");
      }
    };
  };
}

class Test {
  private name: string;
  constructor(name: string) {
    console.log(name);
    this.name = name;
  }
}

const t = addDecorator()(Test); // 包装一下Test类

const t1 = new t("test");
t1.getDecorator();

这里我们用工厂函数返回一个装饰器函数,然后用这个返回的装饰器函数去包装一下 Test 类,TypeScript 就能感知到 getDecorator 函数被添加到了 Test 类上,代码就不会有任何报错了,我们虽然没有用@的装饰器的语法,但我们也没有改变 Test 类,是装饰器的另一种实现,运行代码:


正确运行,没有问题
原文链接

相关文章

  • TS装饰器初体验,用装饰器管理koa接口

    typescript中的装饰器有很多种,比如类装饰器、方法装饰器、属性装饰器等等,先看看装饰器的定义吧,下面以类装...

  • TypeScript基础入门之装饰器(三)

    转载 TypeScript基础入门之装饰器(三) 继续上篇文章[TypeScript基础入门之装饰器(二)] 访...

  • TypeScript: 类的装饰器(三)

    带参数的类的装饰器 学习 python 的同学应该知道,python 中也有装饰器,而且 python 中的众多框...

  • TypeScript基础入门之装饰器(二)

    转发 TypeScript基础入门之装饰器(二) 装饰器求值 如何应用装饰器应用于类内的各种声明的顺序: 对每个实...

  • TypeScript: 类的装饰器(二)

    类的装饰器执行时机 接上文,我们引出了 TypeScript 类的装饰器后,接下来,去挖掘下它的特性 PS:上文,...

  • TypeScript 装饰器

    TypeScript 与 ES6 的装饰器? ES6 的装饰器是一种函数,写成@ + 函数名。它可以放在类和类方法...

  • TypeScript: 类的装饰器(一)

    假设我有一个汽车工厂,每天都在生产汽车,他们都有统一的名字和价格,都可以在公路上开,那么,我们很容易写出如下代码:...

  • TypeScript——装饰器(三)

    访问器装饰器 访问器装饰器声明在一个访问器的声明之前(紧靠着访问器声明)。 访问器装饰器应用于访问器的 属性描述符...

  • 装饰器

    """@装饰器- 普通装饰器- 带参数的装饰器- 通用装饰器- 装饰器装饰类- 内置装饰器- 缓存装饰器- 类实现...

  • 如何配置React项目直接使用TypeScript包(babel

    上期我们说到了TypeScript装饰器(decorators)和JavaScript装饰器编译出的代码不同,我们...

网友评论

      本文标题:TypeScript: 类的装饰器(三)

      本文链接:https://www.haomeiwen.com/subject/uskvqhtx.html