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 方法装饰器实现。
相关推荐
酷酷的威朗普1 小时前
医院绩效考核系统
javascript·css·vue.js·typescript·node.js·echarts·html5
前端李易安13 小时前
Webpack 热更新(HMR)详解:原理与实现
前端·webpack·node.js
Ztiddler1 天前
【npm设置代理-解决npm网络连接error network失败问题】
前端·后端·npm·node.js·vue
前端青山1 天前
webpack进阶(一)
前端·javascript·webpack·前端框架·node.js
老攀呀1 天前
安装多个nodejs版本(nvm)
node.js
佚名程序员1 天前
【Node.js】全面解析 Node.js 安全最佳实践:保护您的应用
安全·node.js
zxg_神说要有光2 天前
快速入门 AI:调用 AI 接口生成 React 组件
前端·javascript·node.js
佚名程序员2 天前
【Node.js】深入理解 V8 JavaScript 引擎
前端·javascript·node.js
赵闪闪1682 天前
Node.js 安装与开发环境配置全指南
node.js
前端与小赵2 天前
什么是Webpack,有什么特点
前端·webpack·node.js