阅读 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
方法装饰器实现。