Nest 装饰器

阅读 NestJS 中文文档 和神光的 Nest 通关秘籍后的学习收获。

在 NestJS 中,装饰器(decorator)无处不在,要想熟练的掌握 Nest 语法,掌握装饰器是必不可少的。

装饰器的基本原理

在 typescript 中, 装饰器是一种特殊类型的声明,它能够被附加到类声明方法属性 或者参数上。

装饰器是一个表达式(express);该表达式被执行后,必须返回一个函数。它会在运行时被调用,被装饰的声明信息做为参数传入。

其写法:@express

牢记:装饰器执行后会返回一个函数

配置使用

装饰器是 ts 中的一个实验性特性,需要单独配置之后,才能才能使用。

第一种方式:命令行

bash 复制代码
# 命令运行配置
tsc --target ES5 --experimentalDecorators

第二种方式:配置 tsconfig.json

json 复制代码
{
  "compilerOptions": {
    "target": "ES5",
    "experimentalDecorators": true // here
  }
}

类装饰器

用来修饰类。

类型申明文件

ts 复制代码
declare type ClassDecorator = <TFunction extends Function>(
  target: TFunction // target 就是构造函数
) => TFunction | void;

案例一:不传递参数

ts 复制代码
function Log(target: Function): void {
  target.prototype.log = function (): void {
    console.log("copyer");
  };
}
​
@Log // 使用语法糖装饰器,在运行是会注入
class Person {
  constructor() {}
}
​
const p = new Person();
p.log(); // 调用装饰器里面的函数

案例二:传递参数

ts 复制代码
function Log(info: string) {
  return function (target: Function): void {
    target.prototype.log = function () {
      console.log(info);
    };
  };
}
​
@Log("copyer") // 先执行 Log 函数,然后再返回一个函数,用于做装饰器表达式(闭包的应用场景)
class Person {
  constructor() {}
}
​
const p = new Person();
p.log();

属性装饰器

用于修饰类的属性。

可以针对属性获取或者设置时,进行一些操作(比如说:拦截)。

类型声明文件

ts 复制代码
declare type PropertyDecorator = (target: Object, key: string | symbol) => void;

案例一:拦截属性的修改

ts 复制代码
function Log(target: any, key: string) {
  delete target[key];
  const _key = "_" + key;
  Object.defineProperty(target, _key, {
    writable: true,
    enumerable: true,
    configurable: true,
  });
​
  const getter = function (this: any) {
    console.log("getter");
    return this[_key];
  };
  const setter = function (this: any, newValue: string) {
    console.log("setter");
    this[_key] = newValue;
  };
  // 重写 get 和 set 方法,进行拦截
  Object.defineProperty(target, key, {
    get: getter,
    set: setter,
    enumerable: true,
    configurable: true,
  });
}
​
class Person {
  @Log
  name: string;
  constructor(name: string) {
    this.name = name;
  }
}

方法装饰器

用于修饰类的方法,进行操作。比如说,给该方法注入一些属性或者特性。

着重理解返回值 descriptor,属性描述符

类型申明文件

ts 复制代码
/**
 * target: 被装饰的类
 * key: 方法名
 * descriptor: 属性描述符
 */
declare type MethodDecorator = <T>(
  target: Object,
  key: string | symbol,
  descriptor: TypePropertyDescript<T>
) => void | TypePropertyDescript<T>;

案例一:获取旧的函数,赋值新的函数

ts 复制代码
function logName(target: Function, key: string, descriptor: any) {
  const originFn = descriptor.value; // 获取原始函数

  // 定义一个新的函数,进行赋值
  let newFn = function (...args: any[]) {
    return originFn.apply(this, args);
  };
  descriptor.value = newFn;
}

class Person {
  name: string;
  constructor(name: string) {
    this.name = name;
  }

  @logName
  getName() {
    return this.name;
  }
}

属性装饰器

用于针对方法中的属性,进行操作,装饰。

ts 复制代码
/**
 * target: 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
 * key:成员的名字
 * descriptor:参数在函数参数列表中的索引
 */
declare type ParamDecorator = <T>(
  target: Object,
  key: string | symbol,
  index: number
) => void;

案例一:简单打印

ts 复制代码
function addName(target: Object, key: string, index: number) {
  console.log(target); // {setName: Function } 类的原型对象
  console.log(key); // setName
  console.log(index); // 0
}

class Person {
  name: string;
  constructor(name: string) {
    this.name = name;
  }

  setName(@addName name: string) {
    this.name = name;
  }
}

学习完装饰器的基本语法之后,可以借助 babel 的转化,变成 es5,看看是怎么实现的。

内置装饰器

上面了解到装饰器的基本使用和原理。接下来就看看 nestjs 到底存在哪些装饰器。

这里只是先了解一下存在哪些装饰器,具体的用法不会过多分析,后续再后面学习过程中,逐渐了解。

  • @Module 申明模块
  • @Controller 申明控制器
  • @Injectable 申明提供者,中间件,守卫等等
  • @Inject 用于属性注入
  • @Optional 依赖可选
  • @Global 申明全局
  • @Catch 指定处理异常
  • @UseFilters 绑定过滤器
  • @UseGuards 绑定守卫
  • @UseInterceptors 绑定拦截器
  • @UsePipes 绑定管道
  • @Query 解析 query 参数
  • @Param 解析动态路由参数
  • @Post post 请求
  • @Get get 请求
  • @Put put 请求
  • @Delete delete 请求
  • @Body 解析 body 参数
  • @SetMetadata 指定元数据
  • @Headers 取出某个或全部请求头
  • @Header 设置请求头
  • @Ip 获取 IP
  • @Session 获取 session
  • @HostParam 获取 host 信息
  • @Request 或者 @Req request 对象
  • @Res 或者 @Response response 对象
  • @Next 中间件
  • @Redirect 重定向
  • @Render 指定渲染用的模版引擎
  • HttpCode 修改状态码

模拟 Get 方法装饰器

ts 复制代码
const Get = (path: string) => {
  // 方法装饰器
  return (
    target: Object,
    key: string,
    descriptor: TypedPropertyDescriptor<any>
  ) => {
    // 保存函数 (getList)
    const saveFn = descriptor.value;
    // 发送请求,获取结果
    axios
      .get(path)
      .then((res) => {
        // 然后回调保存的函数
        saveFn({ data: res.data });
      })
      .catch((err) => {
        saveFn({ err });
      });
  };
};

class Controller {
  constructor() {}

  @Get("/cats")
  getList(res) {
    console.log("res======>", res);
  }
}

总结

  • Typescript 中的装饰器是一个实验室语法,需要自己配置 experimentalDecorators;其表达式为 @express,返回一个函数
  • 装饰器分为四种:类装饰器、方法装饰器、属性装饰器、参数装饰器。着重理解各个装饰器的参数及类型。
  • 总结了 nestjs 中的多个内置装饰器
  • 简单模拟实现了一下 @Get 方法装饰器实现。
相关推荐
神仙别闹4 小时前
基于VUE+Node.JS实现(Web)学生组队网站
前端·vue.js·node.js
BXCQ_xuan6 小时前
基于Node.js的健身会员管理系统的后端开发实践
后端·mysql·node.js
wt_cs6 小时前
身份证实名认证接口数字时代的信任基石-node.js实名认证集成
开发语言·node.js·php
李剑一8 小时前
写一个vitepress新建文章脚本,自动化创建链接,别再手写了!
前端·node.js·vitepress
名字越长技术越强1 天前
Node.js学习
学习·node.js
知识分享小能手1 天前
JavaScript学习教程,从入门到精通,Ajax与Node.js Web服务器开发全面指南(24)
开发语言·前端·javascript·学习·ajax·node.js·html5
dwqqw1 天前
opencv图像库编程
前端·webpack·node.js
layman05281 天前
node.js 实战——(fs模块 知识点学习)
javascript·node.js
本本啊1 天前
node 启动本地应用程序并设置窗口大小和屏幕显示位置
前端·node.js
全栈派森1 天前
Next15 + Prisma + Auth5 实战讲解
react.js·node.js·next.js