Maison > interface Web > js tutoriel > le corps du texte

Analyse pratique de TypeScript dans les projets de nœuds

不言
Libérer: 2018-07-23 11:32:45
original
1605 Les gens l'ont consulté

Le contenu partagé avec vous dans cet article concerne l'analyse pratique de TypeScript dans les projets de nœuds. Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer.

TypeScript peut être compris comme un sur-ensemble de JavaScript, ce qui signifie qu'il couvre toutes les fonctions JavaScript et possède sa propre syntaxe unique.
Un nouveau projet récent a lancé le parcours TS consistant à se heurter à des pièges, et j'aimerais partager avec vous quelques routines dont vous pouvez apprendre.

Pourquoi choisir TS

En tant que langage compilé statiquement fortement typé produit par Juhard Company, ce langage existe depuis plusieurs années, je crois que sous la maintenance de la communauté, il est devenu un. Une langue très stable.
Nous savons que JavaScript est un langage de script interprété de manière dynamique et faiblement typé. Dynamicity apporte beaucoup de commodité. Nous pouvons modifier les types de variables à volonté pendant l'exécution du code pour atteindre l'objectif souhaité.
Mais en même temps, c'est une arme à double tranchant. Lorsqu'un énorme projet apparaît devant vous et confronté à une logique extrêmement complexe, il vous est difficile de dire de quel type est une certaine variable à travers le code et que faut-il faire avec cette variable. Quoi, il est très probable que vous entrez accidentellement dans une fosse.

La compilation statique fortement typée peut apporter de nombreux avantages, le plus important étant qu'elle peut aider les développeurs à éliminer certains problèmes imprudents :
Analyse pratique de TypeScript dans les projets de nœuds

L'image montre le dix principales exceptions parmi les milliers de projets comptés par rollbar

Il n'est pas difficile de voir qu'il y a plus d'exceptions causées par une inadéquation de type et des variables vides que vous n'osez l'admettre.
Par exemple
Analyse pratique de TypeScript dans les projets de nœudsCela a été grandement amélioré dans TS. Toute référence à une variable doit spécifier son propre type. Que pouvez-vous utiliser dans le code et quelles méthodes sont prises en charge ? ci-dessus :
Analyse pratique de TypeScript dans les projets de nœudsCette invite sera donnée aux développeurs pendant les périodes de développement et de compilation pour éviter d'avoir à la modifier après la découverte de problèmes après la mise en ligne.

Un autre avantage apporté par les types compilés statiquement concerne les signatures de fonctions.
Comme mentionné ci-dessus, comme il s'agit d'un langage de script dynamique, il est difficile pour un éditeur de vous indiquer correctement pendant le développement quels paramètres doivent être transmis à une fonction que vous souhaitez appeler et quel type de retour la fonction renverra. . valeur.

Analyse pratique de TypeScript dans les projets de nœuds

Dans TS, pour une fonction, vous devez d'abord définir les types de tous les paramètres et le type de la valeur de retour.
De cette façon, lorsque la fonction est appelée, nous pouvons clairement voir l'effet de cette fonction :
Analyse pratique de TypeScript dans les projets de nœuds

Ce sont les deux fonctionnalités les plus élémentaires qui peuvent rendre le programme plus stable. , bien sûr, il y a plus de fonctions dans TS : TypeScript | Handbook

Application de TypeScript dans le nœud

Sur le site officiel de TS, il existe un grand nombre d'exemples, parmi lesquels vous pouvez find L'exemple de la version Express est légèrement modifié pour cela et appliqué à un projet koa.

Dépendances de l'environnement

Avant d'utiliser TS, vous devez préparer ces choses :

  1. Code VS, les deux sont extrêmement difficiles . Produit par la société et développé par TS, cet éditeur est actuellement celui avec le plus haut support pour TS

  2. La version 8.11 ou supérieure de Node.js est recommandée

  3. <.>
  4. , installez TS globalement, la commande tsc utilisée pour la compilation est ici npm i -g typescript

  5. , installez nodemon globalement, actualisez automatiquement le programme serveur après la compilation tsc npm i -g nodemon

  • Manuel officiel

  • Exemples officiels express

Et certains utilisés dans le projet Dépendances principales :

  1.  : Un package de base dont dépendent un grand nombre de packages de décorateurs pour injecter des données reflect-metadata

  2. : Utiliser des décorateurs pour développer koa-router routing-controllers

  3.  : Opérations de base de données abstraites sequelize

  4.  : La version décorateur de ce qui précède plug-in, utilisez sequelize-typescript

Structure du projet

lors de la définition des entités. Tout d'abord, publiez la structure du projet en cours :

.
├── README.md
├── copy-static-assets.ts
├── nodemon.json
├── package-lock.json
├── package.json
├── dist
├── src
│   ├── config
│   ├── controllers
│   ├── entity
│   ├── models
│   ├── middleware
│   ├── public
│   ├── app.ts
│   ├── server.ts
│   ├── types
│   └── utils
├── tsconfig.json
└── tslint.json
Copier après la connexion
est le répertoire de développement principal, où se trouvent tous les codes TS. Après compilation, un dossier

au même niveau que src sera généré. Ce dossier est le code réel du moteur src à exécuter. distSous node, le code principal est divisé selon la structure suivante (ajouter ou supprimer selon la situation réelle de votre projet) :

|dossier|desc

1 controllers 用于处理接口请求,原appsroutes文件夹。
2 middleware 存放了各种中间件、全局 or 自定义的中间件
3 config 各种配置项的位置,包括端口、log路径、各种巴拉巴拉的常量定义。
4 entity 这里存放的是所有的实体定义(使用了sequelize进行数据库操作)。
5 models 使用来自entity中的实体进行sequelize来完成初始化的操作,并将sequelize对象抛出。
6 utils 存放的各种日常开发中提炼出来的公共函数
7 types 存放了各种客制化的复合类型的定义,各种结构、属性、方法返回值的定义(目前包括常用的Promise版redis与qconf)

controllers

controllers只负责处理逻辑,通过操作model对象,而不是数据库来进行数据的增删改查

鉴于公司绝大部分的Node项目版本都已经升级到了Node 8.11,理所应当的,我们会尝试新的语法。  
也就是说我们会抛弃Generator,拥抱async/await  。

使用KoaExpress写过接口的童鞋应该都知道,当一个项目变得庞大,实际上会产生很多重复的非逻辑代码:

router.get('/', ctx => {})
router.get('/page1', ctx => {})
router.get('/page2', ctx => {})
router.get('/page3', ctx => {})
router.get('/pageN', ctx => {})
Copier après la connexion

而在每个路由监听中,又做着大量重复的工作:

router.get('/', ctx => {
  let uid = Number(ctx.cookies.get('uid'))
  let device = ctx.headers['device'] || 'ios'
  let { tel, name } = ctx.query
})
Copier après la connexion

几乎每一个路由的头部都是在做着获取参数的工作,而参数很可能来自headerbody甚至是cookiequery

所以,我们对原来koa的使用方法进行了一个较大的改动,并使用routing-controllers大量的应用装饰器来帮助我们处理大部分的非逻辑代码。

原有router的定义:

module.exports = function (router) {
  router.get('/', function* (next) {
    let uid = Number(this.cookies.get('uid'))
    let device = this.headers['device']
    
    this.body = {
      code: 200
    }
  })
}
Copier après la connexion

使用了TypeScript与装饰器的定义:

@Controller
export default class {
  @Get('/')
  async index (
    @CookieParam('uid') uid: number,
    @HeaderParam('device') device: string
  ) {
    return {
      code: 200
    }
  }
}
Copier après la connexion

为了使接口更易于检索、更清晰,所以我们抛弃了原有的bd-router的功能(依据文件路径作为接口路径、TS中的文件路径仅用于文件分层)。  
直接在controllers下的文件中声明对应的接口进行监听。

middleware

如果是全局的中间件,则直接在class上添加@Middleware装饰器,并设置type: 'after|before'即可。  
如果是特定的一些中间件,则创建一个普通的class即可,然后在需要使用的controller对象上指定@UseBefore/@UseAfter(可以写在class上,也可以写在method上)。

所有的中间件都需要继承对应的MiddlewareInterface接口,并需要实现use方法

// middleware/xxx.ts
import {ExpressMiddlewareInterface} from "../../src/driver/express/ExpressMiddlewareInterface"

export class CompressionMiddleware implements KoaMiddlewareInterface {
  use(request: any, response: any, next?: Function): any {
    console.log("hello compression ...")
    next()
  }
}

// controllers/xxx.ts
@UseBefore(CompressionMiddleware)
export default class { }
Copier après la connexion

entity

文件只负责定义数据模型,不做任何逻辑操作

同样的使用了sequelize+装饰器的方式,entity只是用来建立与数据库之间通讯的数据模型。

import { Model, Table, Column } from 'sequelize-typescript'

@Table({
  tableName: 'user_info_test'
})
export default class UserInfo extends Model<userinfo> {
  @Column({
    comment: '自增ID',
    autoIncrement: true,
    primaryKey: true
  })
  uid: number

  @Column({
    comment: '姓名'
  })
  name: string

  @Column({
    comment: '年龄',
    defaultValue: 0
  })
  age: number

  @Column({
    comment: '性别'
  })
  gender: number
}</userinfo>
Copier après la connexion

因为sequelize建立连接也是需要对应的数据库地址、账户、密码、database等信息、所以推荐将同一个数据库的所有实体放在一个目录下,方便sequelize加载对应的模型  
同步的推荐在config下创建对应的配置信息,并添加一列用于存放实体的key。  
这样在建立数据库链接,加载数据模型时就可以动态的导入该路径下的所有实体:

// config.ts
export const config = {
  // ...
  mysql1: {
    // ... config
+   entity: 'entity1' // 添加一列用来标识是什么实体的key
  },
  mysql2: {
    // ... config
+   entity: 'entity2' // 添加一列用来标识是什么实体的key
  }
  // ...
}

// utils/mysql.ts
new Sequelize({
  // ...
  modelPath: [path.reolve(__dirname, `../entity/${config.mysql1.entity}`)]
  // ...
})
Copier après la connexion

model

model的定位在于根据对应的实体创建抽象化的数据库对象,因为使用了sequelize,所以该目录下的文件会变得非常简洁。  
基本就是初始化sequelize对象,并在加载模型后将其抛出。

export default new Sequelize({
  host: '127.0.0.1',
  database: 'database',
  username: 'user',
  password: 'password',
  dialect: 'mysql', // 或者一些其他的数据库
  modelPaths: [path.resolve(__dirname, `../entity/${configs.mysql1.entity}`)], // 加载我们的实体
  pool: { // 连接池的一些相关配置
    max: 5,
    min: 0,
    acquire: 30000,
    idle: 10000
  },
  operatorsAliases: false,
  logging: true // true会在控制台打印每次sequelize操作时对应的SQL命令
})
Copier après la connexion

utils

所有的公共函数,都放在这里。  
同时推荐编写对应的索引文件(index.ts),大致的格式如下:

// utils/get-uid.ts
export default function (): number {
  return 123
}

// utils/number-comma.ts
export default function(): string {
  return '1,234'
}

// utils/index.ts
export {default as getUid} from './get-uid'
export {default as numberComma} from './number-comma'
Copier après la connexion

每添加一个新的util,就去index中添加对应的索引,这样带来的好处就是可以通过一行来引入所有想引入的utils

import {getUid, numberComma} from './utils'
Copier après la connexion

configs

configs下边存储的就是各种配置信息了,包括一些第三方接口URL、数据库配置、日志路径。  
各种balabala的静态数据。  
如果配置文件多的话,建议拆分为多个文件,然后按照utils的方式编写索引文件。

types

这里存放的是所有的自定义的类型定义,一些开源社区没有提供的,但是我们用到的第三方插件,需要在这里进行定义,一般来说常用的都会有,但是一些小众的包可能确实没有TS的支持,例如我们有使用的一个node-qconf

// types/node-qconf.d.ts
export function getConf(path: string): string | null
export function getBatchKeys(path: string): string[] | null
export function getBatchConf(path: string): string | null
export function getAllHost(path: string): string[] | null
export function getHost(path: string): string | null
Copier après la connexion

类型定义的文件规定后缀为 .d.ts  
types下边的所有文件可以直接引用,而不用关心相对路径的问题(其他普通的model则需要写相对路径,这是一个很尴尬的问题)。

目前使用TS中的一些问题

Analyse pratique de TypeScript dans les projets de nœuds当前GitHub仓库中,有2600+的开启状态的issues,筛选bug标签后,依然有900+的存在。  
所以很难保证在使用的过程中不会踩坑,但是一个项目拥有这么多活跃的issues,也能从侧面说明这个项目的受欢迎程度。

目前遇到的唯一一个比较尴尬的问题就是:
引用文件路径一定要写全。。

import module from '../../../../f**k-module'
Copier après la connexion

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal