随着应用的庞大,项目中 JavaScript 的代码也会越来越臃肿,这时候许多 JavaScript 的语言弊端就会愈发明显,而 TypeScript 的出现,就是着力于解决 JavaScript 语言天生的弱势:静态类型。

前端开发 QQ 群:377786580

这篇文章首发于我的个人博客 《听说》,系列目录:

  • 《从 JavaScript 到 TypeScript 1 - 什么是 TypeScript》
  • 《从 JavaScript 到 TypeScript 2 - 基础特性和类型推导》
  • 《从 JavaScript 到 TypeScript 3 - 引入和编译》
  • 《从 JavaScript 到 TypeScript 4 - 装饰器和反射》
  • 《从 JavaScript 到 TypeScript 5 - express 路由进化》
  • 《从 JavaScript 到 TypeScript 6 - vue 引入 TypeScript》

在上一篇文章 《从 JavaScript 到 TypeScript 4 - 装饰器和反射》 我们介绍了装饰器和反射,在这篇文章中,我们会把这两个特性引入,并且在 express 上,实现一层全新的路由封装。

express 路由

首先我们来看一个简单的 express 路由 (router):

// 对网站首页的访问返回 "Hello World!"
app.get('/', function (req: Request, res: Reponse) {res.send('Hello World!')
})app.post('/user', function (req: Request, res: Reponse) {res.send(`User Id ${req.query.id}`)
})

在上面的路由代码我们演示了一个普通流水线式的路由。

基于上一篇文章中我们学到的装饰器和反射的知识,我们将要实现 路由的配置通过装饰器实现,并且实现一层路由逻辑的封装。

路由进化

基于装饰器和反射,我们要实现的路由最终效果是这样的:

class Home {@path('/user')@httpGetuser (id: string) {return `User Id ${id}`}
}
GET  HTTP/1.1
Host: /user?id=tasaid.com

这段代码相比传统的路由配置,优点如下:

  • 将路由的配置抽离成为了装饰器,让整个 router 函数内部只需要处理业务逻辑即可,路由配置简单明了
  • 隐藏 reqres,每个 router 直接返回结果即可,无需自己再输出结果

装饰器: HTTP Method

我们先编写 HTTP Method 的装饰器,我们将实现两个装饰器,分别叫做 httpGethttpPost,对应 HTTP Method 的 GET/POST

原理上,我们会将 router 配置的数据都挂到使用装饰器的方法上。

import 'reflect-metadata'export const symbolHttpMethodsKey = Symbol("router:httpMethod")export const httpGet = function (target: any, propertyKey: string) {// 挂载到调用装饰器的方法上Reflect.defineMetadata(symbolHttpMethodsKey, 'get', target, propertyKey)
}export const httpPost = function (target: any, propertyKey: string) {Reflect.defineMetadata(symbolHttpMethodsKey, 'post', target, propertyKey)
}

装饰器: path

有了上面 HTTP Method 装饰器的实现,我们再实现 path 装饰器将会很简单。

当然,我们还可以在 path 中实现对原方法的封装:隐藏 reqres,并对 router 的输出结果进行封装。

注意这里使用的是装饰器工厂:

import 'reflect-metadata'export const symbolPathKey = Symbol.for('router:path')export let path = (path: string): Function => {return function (target: any, propertyKey: string, descriptor: TypedPropertyDescriptor<Function>) {Reflect.defineMetadata(symbolPathKey, path, target, propertyKey)if (!descriptor.value) return// 覆盖掉原来的 router method,在外层做封装let oldMethod = descriptor.valuedescriptor.value = function (req: Request, res: Response) {const params = Object.assign({}, req.body, req.query)let methodResult = oldMethod.call(this, params)// 输出返回结果res.send(methodResult)}}
}

Router? Controller!

现在,我们需要将所有的 Router 按照自己的业务规则/或者自定义的其他规则进行归类 —— 然后提取出对应的 Class,例如下面的 User Class 就是把用户信息所有的 router 都归类在一起:

class User {@httpPost@path('/user/login')login() { }@httpGet@path('/user/exit')exit() { }
}

然后在 express 配置的入口逻辑那里,把 class 对应的方法遍历一遍,然后使用 reflect-metadata 反射对应的 router 配置即可:

import 'reflect-metadata'
// 装饰器挂载数据的 key
import { symbolHttpMethodsKey, symbolPathKey } from './decorators'const createController = (app: Express) => {let user = new User()for (let methodName in user) {let method = user[methodName]if (typeof method !== 'function') break// 反射得到挂载的数据let httpMethod = Reflect.getMetadata(symbolHttpMethodsKey, user, methodName)let path = Reflect.getMetadata(symbolPathKey, user, methodName)// app.get('/', () => any)app[httpMethod](path, method)}
}

至此,我们的 express 路由进化完毕,效果如下:

完整的例子可以参考我的 Github。

结语

装饰器目前在 ECMAScript 新提案中的 建议征集的第二阶段(Stage 2),由于装饰器在其他语言中早已实现,例如 Java 的注解(Annotation) 和 C# 的特性(Attribute),所以纳入 ECMAScript 规范只是时间问题了。

装饰器来装饰路由,并且封装 router 操作的的思路缘起 .NET MVC 架构:

angular 2.x 使用也引入了装饰器作为核心开发,随着规范的推进,相信装饰器进入大家视野,应用的场景也会越来越多。

在下一篇文章 《从 JavaScript 到 TypeScript 6 - Vue 引入 TypeScript》 中,我们将介绍如何在 Vue 中引入 TypeScript。

TypeScript 中文网:https://tslang.cn/

TypeScript 视频教程:《TypeScript 精通指南》

从 JavaScript 到 TypeScript 5 - 路由进化相关推荐

  1. 从 JavaScript 到 TypeScript 6 - Vue 引入 TypeScript

    随着应用的庞大,项目中 JavaScript 的代码也会越来越臃肿,这时候许多 JavaScript 的语言弊端就会愈发明显,而 TypeScript 的出现,就是着力于解决 JavaScript 语 ...

  2. 设置WebStorm像VSCode一样每行代码结尾自动格式化加入“;”分号(JavaScript、TypeScript格式化)

    Ctrl+Shift+S→编辑器→Code Style→JavaScript或TypeScript→Punctuation 1.每行代码结尾自动加上;分号: Use(下拉框选Use)semiconlo ...

  3. 简单探讨JavaScript 与 TypeScript之间的联系

    这篇文章主要介绍了 JavaScript 与 TypeScript之间的联系,JavaScript,也称为 JS,是一种符合 ECMAScript 规范的编程语言.这是一个高级别的.通常是即时编译的. ...

  4. 对比Javascript和TypeScript

    JavaScript 特点: 1. JavaScript是解释性脚本语言,不需要编译,可以直接在浏览器中解释执行 2. 是基于对象的语言,可以创建对象并使用现有对象 3. 是弱类型.动态语言,基于对象 ...

  5. JavaScript 和 typeScript 中的 import、from

    From:https://segmentfault.com/a/1190000018249137?utm_source=tag-newest Github - allowSyntheticDefaul ...

  6. 浏览器解析jsx_简单理解JavaScript,TypeScript和JSX

    原标题:简单理解JavaScript,TypeScript和JSX Java: 基本概念: Java一种直译式脚本语言,是一种动态类型.弱类型.基于原型的语言,内置支持类型.它的解释器被称为Java引 ...

  7. Javascript实现前端简单路由

    http://www.helloweba.com/view-blog-385.html WEB开发中路由概念并不陌生,我们接触到的有前端路由和后端路由.后端路由在很多框架中是一个重要的模块,如Thin ...

  8. 从JavaScript到TypeScript,Pt。 IIB:使用类,接口和混合器进行设计

    Class-based design has become such an instinct that many developers can't imagine any alternative. 基 ...

  9. JavaScript 和 TypeScript 交叉口 —— 类型定义文件(*.d.ts)

    在 <从 JavaScript 到 TypeScript 系列> 文章我们已经学习了 TypeScript 相关的知识. TypeScript 的核心在于静态类型,我们在编写 TS 的时候 ...

最新文章

  1. 【廖雪峰python入门笔记】tuple_创建单元素
  2. 一阶和二阶微分方程的物理意义???
  3. 案例分析 | SAP如何帮助企业实现端到端的数字化供应链管理
  4. 网红送餐无人车被指用人冒充AI始末:没有人工,就没有智能
  5. setDAta 字符串拼接
  6. 空指针异常是什么原因_睡觉时,突然抖了一下,脚踏空,是什么原因?
  7. 海南电网全力支持新能源发展
  8. Wannafly挑战赛19
  9. java多态+多态中隐含的问题
  10. python求偏度系数_用 Python 讲解偏度和峰度
  11. 【Xamarin挖墙脚系列:Xamarin.IOS机制原理剖析】
  12. Oracle数据库中查看所有表和字段以及表注释.字段注释
  13. 用 logisim写一个 cpu
  14. Linux查看增量文件,Linux 利用 rsync 命令提取增量文件
  15. 省市级联实现,并根据IP自动获取省市
  16. 软考高级 真题 2010年下半年 信息系统项目管理师 综合知识
  17. 【matlab图像处理】图像处理的经典操作
  18. Python接口自动化之ddt学习笔记
  19. 201919102004张雪婷(在虚拟机中安装)
  20. Revit二次开发--为管道添加标注

热门文章

  1. MySQL笔记14:常用命令
  2. oracle: 在sqlplus中,执行sql语句
  3. Socket通信(一)
  4. Jinja2模板引擎简介
  5. Snapchat何以在Facebook包围下“杀出重围”?
  6. req.xhr在express中的应用
  7. SSL介绍与Java实例
  8. 阿里云产品搭建web应用梳理
  9. Java IO: 网络
  10. 操作系统概念学习笔记 11 进程同步(一)