TS

TypeScript 是一种由微软开发的自由和开源的编程语言。它是 JavaScript 的一个超集,而且本质上向这个语言添加了可选的静态类	型和基于类的面向对象编程。
TypeScript 扩展了 JavaScript 的句法,所以任何现有的 JavaScript 程序可以不加改变的在 TypeScript 下工作。 TypeScript 是为大型应用之开发而设计,而编译时它产生 JavaScript 以确保兼容性。
这段是我在网上扒下来的

为什么要用TS对express进行封装呢?

主要是为了用ts里面的装饰器,虽然装饰器已经是es7里面的一个提案了,但是在js里面
使用的话还需要用babel进行配置(太麻烦了,图省事所以用Ts)

我们先来了解一下什么是装饰器

装饰器(Decorator) 仅提供定义劫持,能够对类及其方法、方法入参、属性的定义
并没有提供任何附加元数据的功能。
主要是为了提供附加的功能

那么TS里面的装饰器如何使用呢

二话不说npm一把梭
npm init -y //使用默认配置
npm i typescript -S //安装ts包
tsc --init //初始化ts配置
mkdir src //创建src目录
mkdir decorators //创建装饰器目录
touch common.ts //创建common 用于辨析而装饰器
touch index.ts //创建index文件
到此为止已经搭建了项目的基本架构

接下来我们介绍一下TS里面有那些类型的装饰器

类装饰器

应用于类的构造函数
参数:target (类)
写法:function classDecorators(target:any){
//我们在这个地方来对象进行操作
//比我我们给类里面的原型加一点东西
target.prototype.usernmae='沉默'
}

属性装饰器

应用于属性上面的装饰器
参数:targte (类),name(当前属性的名字)
写法:
function attrDecorators(target:any,name:string){
target[name]=150 //我们给当前属性赋了一个值
}

方法装饰器

应用于方法上面的装饰器
参数:targte (类),name(当前方法的名字),descriptor (当前方法的描述对象)
写法:
function funcDecorators(target:any,name:string,descriptor:PropertyDescriptor){
//我们在这个装饰器里面来写一些,在每次执行的时候打印一个时间
let origin=descriptor.value;//这个就是当前方法的内容,我们给他保存起来
descriptor.value=function(){
console.log(new Date())
//执行我们保存的那个方法 arguments是传进来的那些参数
return origin.apply(this,arguments)
}
return descriptor
}

方法参数的装饰器

应用于方法参数上面的装饰器
参数:target(类),name(当前参数方法的名称),index(按当前参数的在形参列表里面的索引值)
function paramDecorators(target:any,name:string,index:number){
//这个装饰器也没有上面例子好举了
}

这是我们讲的ts的装饰器,我们一起加在一个类上面,来看看他的执行顺序是上面样的



我们可以看到先走的是属性的装饰器,之后是参数在是方法然后是类

我看别人的装饰器里面都能传值,为什么我看你这个不能呢!

不要着急,马上就会讲到,TS里面还有一个叫装饰器工厂的装饰器就是用来完成这个工作的。
装饰器工厂的定义方法就是返回的是一个方法
来看例子
function classDesc(path:string){
//这就是一个装饰器工厂,上面的path就是你可以传进来的值
console.log(path,'class')
return (target:any)=>{
console.log(typeof target,'class')
}
}
其他类型的装饰器的写法也都类似与这样,只不过是参数不一样

接下来我们讲讲js里面的元数据

元数据即为描述数据的数据,也有个称呼叫
注解(Annotation) 仅提供附加元数据支持,并不能实现任何操作。需要另外的 Scanner 根据元数据执行相应操作。
但是我一听到注解就像Java里面的东西
总而言之,装饰器和注解是不一样的,我上面有讲过装饰器的概念,主要是为了提供附加功能,注解不提供这些,它只提供元数据的支持,不能操作任何东西,所以只能根据元数据来实现具体的操作。

知道元数据之后我们就可以来封装标题上面所讲的装饰器了,封装那些需要用到

我们最终会是实现这些装饰器
Controller Get Post Body Query 等
之前我们以及创建了common.ts文件,那么就在这里先创建第一个装饰器(Controller)
const PATH_METADETA='path';
const PATH_METADETA = "path";
const PARAMS_METADETA = "params";
function Controller(path:string):ClassDecorator{
//创建装饰器工厂,可以用来接收参数,上面以及讲过了
return (target)=>{
/*
给当前类添加一个元数据
Reflect.defineMetadata用来添加元数据,总共有四个值第一个是key,唯一的,
第二个是值,第三个是当前对象,第四个是方法名,但我们当前只给类设置元数据,就不需要
填方法
为什么要设置元数据呢,装饰器本来就是用来扩展方法的,但是他是用来对本方法进行扩展的,
在此装饰器里面我们拿不到,具体的数据,所以我们用元数据去设置具体的数据,在其他地方进行
通用的注册使用,这个装饰器的作用就是用设置元数据的(我也不知道这样讲能不能明白:))
*/
Reflect.defineMetadata(PATH_METADETA, path, target);//当前装饰器传过来
//的数据给设置进入了类的元数据里面了,日常的时候这个类并不影响我们的使用
}
}
//我们需要编写Post Get 这些的方法,本质上这些方法除了Post,Get这些不一样,传过来的东西都
//是一样的
function createdMethod(methods: string) {
return (path: string): MethodDecorator => {
return (target: any, key: string | symbol, descriptor: any) => {
//给当前方法设置了一个
Reflect.defineMetadata(PATH_METADETA, path, target, key);
//添加方法元数据,描述当前方法为什么方法
Reflect.defineMetadata(METHOD_METADETA, methods, target, key);
};
};
}
目前我们先写这两个装饰器,之后在写params的装饰器

装饰器虽然是写好了

但是我们在那里去用呢,不会这么简单吧。
当然不会那么简单,我们现在还需要一个注册的地方,我们需要让express拿到装饰器装饰上去的
元数据。 我们在decorators里面在建一个文件 叫 register.ts 用来注册我们装饰的类
下面是代码
import {Router} from 'express';
function register(app:any,controller:Array<any>){
const router=Router();
controller.forEach((v:any)=>{
//这个v就是类
//获取当前类key为path的元数据 也就是之前我们装饰器设置的值
let classPath=Reflect.getMetadata('path',v);
//遍历当前属性,查询当前类属性上面有哪些元数据
for(const key in new v()){
//这个getMetadata里面的key是当前遍历的方法的名称
//也就拿到当前方法设置的元数据
let attrMethod = Reflect.getMetadata('method', new v(), key);
let attrPath = Reflect.getMetadata('path', new v(), key);
//我们在定义一个回调方法,这个就是express的回调方法
let fn:any=(req,res,next)=>{
//我们先把我们当前的方法给执行一下,在传两个参数(这个方法就是@Post@Get这个中下面的方法)
let result=new v()[key].apply(new v(),[req,res]);
if (result instanceof Promise) {
result.then(value => {
!res.headersSent && res.send(value);
}).catch(err => {
next(err)
})
} else if (result !== undefined) {
!res.headersSent && res.send(result);
} }
//组装一下路由的路径
let routerParams = [classPath + attrPath]
//在添加回调
routerParams.push(fn)
//去调用router方法
router[attrMethod].apply(router, routerParams)
}
//用来解决body
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: false }))
app.use(router)//使用路由
})
}
在index.ts 里面启动express并注册,我们的装饰器应该就能和router联动起来了
  register(app,[UserController]);

  var server = app.listen(3122, function () {
var host = server.address().address;
var port = server.address().port;
console.log('Example app listening at http://%s:%s', host, port);
})
自此也就算是写完了!我也是研究了一下午,看了github上面的一些主流的框架的源码,剥离出来的简单的版本

我也是一个没干多久小菜鸟,希望这个篇文]章对你们有所帮助
我自己写的那个项目在[github](https://github.com/mrzhouxl/express-decorator)

ts装饰器的用法,基于express创建Controller等装饰器的更多相关文章

  1. 简单说明Python中的装饰器的用法

    简单说明Python中的装饰器的用法 这篇文章主要简单说明了Python中的装饰器的用法,装饰器在Python的进阶学习中非常重要,示例代码基于Python2.x,需要的朋友可以参考下   装饰器对与 ...

  2. 一篇文章搞懂Python装饰器所有用法

    01. 装饰器语法糖 如果你接触 Python 有一段时间了的话,想必你对 @ 符号一定不陌生了,没错 @ 符号就是装饰器的语法糖. 它放在一个函数开始定义的地方,它就像一顶帽子一样戴在这个函数的头上 ...

  3. 在express中使用ES7装饰器构建路由

    在Java的Spring框架中,我们经常会看到类似于@Controller这样的注解,这类代码能够极大的提高我们代码的可读性和复用性.而在Javascript的ES7提案中,有一种新的语法叫做deco ...

  4. Python函数装饰器高级用法

    在了解了Python函数装饰器基础知识和闭包之后,开始正式学习函数装饰器. 典型的函数装饰器 以下示例定义了一个装饰器,输出函数的运行时间: 函数装饰器和闭包紧密结合,入参func代表被装饰函数,通过 ...

  5. Python的装饰器实例用法小结

    这篇文章主要介绍了Python装饰器用法,结合实例形式总结分析了Python常用装饰器的概念.功能.使用方法及相关注意事项 一.装饰器是什么 python的装饰器本质上是一个Python函数,它可以让 ...

  6. Python @函数装饰器及用法

    1.函数装饰器的工作原理 函数装饰器的工作原理是怎样的呢?假设用 funA() 函数装饰器去装饰 funB() 函数,如下所示: #funA 作为装饰器函数 def funA(fn): #... fn ...

  7. 基于linux信号的timeout装饰器

    在做基于ray的分布式任务处理时,偶尔遇到由于ray集群不稳定导致的长时间连接不上,进而导致程序卡死,无法向后端返回任务状态的情况.但是ray的初始化函数本身未实现超时机制,因此设计基于多线程+信号的 ...

  8. Python @函数装饰器及用法(超级详细)

    函数装饰器的工作原理是怎样的呢?假设用 funA() 函数装饰器去装饰 funB() 函数,如下所示: #funA 作为装饰器函数 def funA(fn): #... fn() # 执行传入的fn参 ...

  9. SiteMesh2-sitemesh.xml的其它映射器的用法

    在sitemesh.xml中做常用的三个映射器,总结如下: 映射器元素的顺序确定优先级.良好的应用程序应使用以下顺序, Parameter query = ParameterDecoratorMapp ...

随机推荐

  1. OpenStack Train版-8.安装neutron网络服务(控制节点)

    安装neutron网络服务(controller控制节点192.168.0.10) 创建neutron数据库 mysql -uroot CREATE DATABASE neutron; GRANT A ...

  2. LINUX - 通信

    为什么三次握手: 让服务端和客户端都知道,自己的收信能力和发信能力没有问题: 第一次:客户端发给服务端--服务端知道了,自己的收信能力和客户端的发信能力没有问题: 第二次:服务端回复客户端--客户端知 ...

  3. 牛客网多校第7场 J Sudoku Subrectangles 【构造】

    题目:戳这里 题意:给一个n*m的矩阵,里面由a~z及A~Z构成,问有多少个子矩阵满足任意一行或一列中都没有相同的字母. 解题思路:左上角和右下角两点可以确定一个矩阵.可以先预处理出来每个点作为一个矩 ...

  4. Leetcode(17)-电话号码的字母组合

    给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合. 给出数字到字母的映射如下(与电话按键相同).注意 1 不对应任何字母. 示例: 输入:"23" 输出:[&quo ...

  5. C++的继承权限

    原文来自于:https://www.cnblogs.com/2018shawn/p/10648408.html 公式: 继承成员对外的访问属性 = Max{继承方式,父类成员访问级别}: ps;以下成 ...

  6. Cortex-M3 内核中悬起标志位细节逻辑

    对于外设中断,如果通过NVIC_DisableIRQ(xxx)关闭对应NVIC里面的使能位,会导致对应中断Pend位置起,如果清除Pend位时不清外设的中断标志位将导致对应Pend位立刻再次置起.所以 ...

  7. STM32 单片机的USART的奇偶校验 误区(坑)

    当STM32的串口配置成带有奇偶校验位的情况下,需要软件校验是否发生奇偶校验错误,硬件只是置起奇偶校验错误标志位,并将错误的数据放到DR寄存器中,同时置起RXEN标志位,如果使能中断还是会正常进入中断 ...

  8. webpack4.0源码解析之esModule打包分析

    入口文件index.js采用esModule方式导入模块文件,非入口文件index1.js分别采用CommonJS和esmodule规范进行导出. 首先,init之后创建一个简单的webpack基本的 ...

  9. js screen size check

    js screen size check js 屏幕尺寸检测 window.screen API screen; window.screen.width; window.screen.height; ...

  10. Chrome Enhanced Protection

    Chrome Enhanced Protection chrome://settings/security?q=enhanced 站内外链跳转拦截 refs xgqfrms 2012-2020 www ...