花式玩转TypeScript类型-我使用swagger的描述文件自动生成类型的npm包供前端使用

8 阅读5分钟

背景:在前端开发中,后端API的类型定义一直是前后端协作的痛点。传统方式下,前端开发者需要手动编写和维护API请求参数和响应数据的类型定义,不仅工作繁琐,而且容易与后端实际接口产生不一致,导致类型错误难以发现。

为了解决这个问题,我探索了一条自动化生成TypeScript类型的完整流程:

graph LR
    A["后端添加<br/>Swagger描述"] --> B["生成<br/>Swagger文档"]
    B --> C["收集OpenAPI<br/>描述文件"]
    C --> D["swagger-codegen-cli<br/>生成TS类型"]
    D --> E["npm类型包<br/>@types规范命名"]
    E --> F["发布到<br/>npm私服"]
    F --> G["npm<br/>install"]
    G --> H["前端<br/>import使用"]

通过这套流程,后端修改接口后,前端只需要重新安装最新的npm包即可获得最新的类型定义,真正实现了类型定义的自动化管理。

swagger

Swagger是一套用于构建、描述、测试和文档化RESTful API的开源框架。它通过在代码中添加注解(Annotations)来自动生成API文档,让后端开发者可以轻松地记录接口信息。

主流实现

  • Java: SpringFox、Swagger Annotations
  • Go: swaggo、go-swagger
  • Python: flasgger、swagger-python
  • Node.js: express-swagger-generator

基本注解示例

以Java SpringBoot为例:

@Api(tags = "用户管理")
@RestController
@RequestMapping("/api/users")
public class UserController {

    @ApiOperation("获取用户详情")
    @GetMapping("/{id}")
    public User getUserById(@ApiParam("用户ID") @PathVariable Long id) {
        return userService.getById(id);
    }

    @ApiOperation("创建用户")
    @PostMapping
    public Result<User> createUser(@RequestBody @Valid CreateUserRequest request) {
        return Result.success(userService.create(request));
    }
}

通过这些注解,Swagger会自动生成完整的API文档,包含请求参数、响应格式、错误码等详细信息。

OpenAPI

OpenAPI规范(原名Swagger规范)是一种与编程语言无关的REST API描述规范。它使用JSON或YAML格式来描述API的结构,包括:

  • 接口路径(endpoints)
  • HTTP方法(GET、POST、PUT、DELETE等)
  • 请求参数和响应结构
  • 认证方式
  • 错误码定义

OpenAPI文档示例

openapi: 3.0.3
info:
  title: 用户中心API
  version: 1.0.0
paths:
  /api/users/{id}:
    get:
      summary: 获取用户详情
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
components:
  schemas:
    User:
      type: object
      properties:
        id:
          type: integer
        username:
          type: string
        email:
          type: string

OpenAPI文档是整个自动化流程的核心,它作为中间桥梁连接了后端实现和前端类型生成。

实际中的swagger返回api描述:

openapi.png

自动生成类型的npm包

使用swagger-codegen-cli

我们使用swagger-codegen-cli-3.0.71.jar来从OpenAPI描述文件生成TypeScript类型定义。

生成命令

java -jar swagger-codegen-cli-3.0.71.jar generate \
  -i openapi.json \
  -l typescript \
  -o ./src/types \
  --additional-properties=modelPropertyNaming=camelCase,supportsES6=true

生成配置选项

参数说明可选值
modelPropertyNaming属性命名风格camelCase、PascalCase、snake_case
supportsES6是否支持ES6true、false
exportInterfaces是否导出接口true、false
enumPropertyNaming枚举命名风格camelCase、PascalCase、UPPER_CASE

生成结果示例

生成的TypeScript类型文件:

export interface User {
  id: number;
  username: string;
  email: string;
  createdAt: string;
}

export interface CreateUserRequest {
  username: string;
  email: string;
  password: string;
}

export interface Result<T> {
  code: number;
  message: string;
  data: T;
}

发布npm包

命名规范

采用@types/{project}-{module}的命名风格,例如:

  • @types/user-center - 用户中心模块
  • @types/order-system - 订单系统
  • @types/product-api - 商品API

这样的命名方式:

  1. 符合npm社区对类型包的约定(@types前缀)
  2. 清晰表明是某个项目或模块的类型定义
  3. 便于前端按需安装

package.json配置

{
  "name": "@types/user-center",
  "version": "1.0.0",
  "description": "用户中心API类型定义",
  "main": "index.d.ts",
  "types": "index.d.ts",
  "publishConfig": {
    "registry": "http://npm.internal.company.com/"
  }
}

下面是我们实际项目中使用的一个示例:

pkg-sub.png

发布到npm私服

# 登录npm仓库
npm login --registry=http://npm.internal.company.com/

# 发布包
npm publish --registry=http://npm.internal.company.com/

使用和更新

前端安装使用

npm install @types/user-center --save-dev --registry=http://npm.internal.company.com/

实际项目中的样子:

  • pkg.png
  • file.png

由截图可以看出由于按typescript的@types规范命名,其跟node的类型包一起放到了@types目录下,并且引入时不需要@types前缀

在代码中使用

  1. 引入,由于符合typescript的类型定义规范,所以可以直接引入类型包的名称而不需要@types前缀

import.png

  1. 使用,由引入可知,如果后端同学定义的类型全面的话会包含每个视图,接口的request,response,error等,所以前端在使用时只需要引入对应的类型即可,例如(这里我将引入的类型重新收集到了一个命名空间中了):

use.png

自动化更新流程

建议将类型生成集成到CI/CD流程中:

  1. 代码提交触发: 后端提交代码时自动运行
  2. 生成类型文件: 执行swagger-codegen生成新的类型定义
  3. 版本更新: 自动递增版本号
  4. 自动发布: 发布到npm私服
  5. 通知前端: 通知前端更新依赖,例如通过企业微信/钉钉通知前端更新依赖
# .gitlab-ci.yml 示例
generate-types:
  stage: build
  script:
    - java -jar swagger-codegen-cli-3.0.71.jar generate \
      -i api/openapi.json \
      -l typescript \
      -o ./types
    - npm version patch
    - npm publish --registry=http://npm.internal.company.com/
  only:
    - main

版本管理策略

  • patch版本: 接口字段的增删改
  • minor版本: 新增接口
  • major版本: 不兼容的接口变更

总结

通过这套基于Swagger自动生成TypeScript类型的方案,我们实现了:

  1. 类型一致性: 前端使用的类型与后端API完全一致,避免了手动维护带来的不同步问题
  2. 开发效率提升: 后端修改接口后,前端可以快速获取最新的类型定义,减少沟通成本
  3. 自动化流程: 集成到CI/CD中,实现零手动干预的类型更新
  4. 规范统一: 统一的命名规范和包管理策略,便于项目管理和维护
  5. 协商协调: 前端和后端需要协商好类型定义的命名规范和位置,确保一致的使用,这需要前后端有很强的沟通意识,和规范的编码习惯。

这套方案特别适合中大型项目,能够有效提升前后端协作效率,减少因为类型不一致导致的线上bug。