npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

vite-plugin-api-types-gen

v0.1.1

Published

根据 Swagger/OpenAPI 文档或运行时 API 响应,自动生成 TypeScript 类型定义的 Vite 插件

Readme

vite-plugin-api-types-gen

English | 简体中文

根据 Swagger / OpenAPI 文档 或 浏览器运行时真实响应,自动生成 TypeScript 类型定义的 Vite 插件。 无需手写接口类型,嵌套对象、数组与树形结构会被自动拆分为可单独引用的命名类型。

🌟 核心特性

  • 🚀 双数据源:既支持 Swagger/OpenAPI 文档(JSON / YAML),也支持在浏览器运行时自动捕获真实响应
  • 🧩 嵌套拆分:嵌套对象、数组元素自动拆为独立 interface,可单独 import type 引用
  • 🌲 树形自引用:children / nodes 等递归字段自动生成自引用类型(如 MenuTreeNode.children?: MenuTreeNode[])
  • 🧾 请求体类型:请求体为对象时同样生成类型(如 CreateUserReq)
  • 📁 单文件 / 多文件:per-api 每个接口一个 ts 文件并生成 index.ts 聚合导出;single 全部写入一个文件
  • ♻️ 双重去重:单次解析内按 Schema 结构指纹去重,per-api 模式下跨文件重复类型自动 import type 复用
  • 🧠 LRU 缓存:避免多次生成相同类型,自动限制内存占用
  • 🗑️ 空文件不落盘:接口没有可生成的类型时不会保留空文件,并会清理陈旧空文件
  • ✋ 捕获手动开启:响应捕获默认关闭,需运行时手动开启,且同一接口默认只生成一次,不会每次请求都生成
  • 🎯 灵活过滤:include / exclude 同时支持字符串包含匹配与正则
  • 🛡️ 无侵入:通过克隆响应解析数据,不影响原请求执行

📦 安装

# npm
npm install vite-plugin-api-types-gen --save-dev

# yarn
yarn add vite-plugin-api-types-gen -D

# pnpm
pnpm add vite-plugin-api-types-gen -D

尚未发布到 npm 时,可使用本地路径安装:

{ "devDependencies": { "vite-plugin-api-types-gen": "file:../vite-plugin-api-types-gen" } }

🚀 快速开始

// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { apiTypesGen } from 'vite-plugin-api-types-gen'

export default defineConfig({
  plugins: [
    vue(),
    apiTypesGen({
      outDir: 'src/api-types',        // 类型输出目录(默认 src/api-types)
      outputMode: 'per-api',          // 每个接口一个 ts 文件 + index.ts 聚合导出
      recursiveKeys: ['children'],    // 树形结构识别字段
      swagger: {
        enabled: true,
        // 支持 http(s) 地址,也支持本地文件(JSON / YAML 均可)
        url: 'http://localhost:8080/v3/api-docs',
        exclude: ['/actuator'],
        typeNameSuffix: 'Ret',        // GET /api/menu/list -> GetMenuListRet
      },
    }),
  ],
})

npm run dev 启动时会自动拉取文档并生成类型到 outDir。

完整的可运行宿主示例(Vue 3)见 examples/host。

⚙️ 配置项说明

顶层配置

| 配置项 | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | outDir | string | src/api-types | 类型文件输出目录(相对于项目根目录) | | outputMode | 'per-api' \| 'single' | 'per-api' | per-api:每个接口一个文件;single:全部写入 api-types.ts | | barrel | boolean | true | per-api 模式下是否生成 index.ts 聚合导出文件 | | allPropertiesOptional | boolean | false | 是否把所有属性都标记为可选 | | recursiveKeys | string[] | ['children','child','nodes','items'] | 递归/树形结构识别字段名,命中且结构与父级一致时生成自引用类型 | | runOnBuild | boolean | false | vite build 阶段是否也执行一次 Swagger 生成 | | lru.maxSize | number | 200 | LRU 缓存条目上限 | | logger | boolean | true | 是否输出插件日志 |

swagger 数据源

| 配置项 | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | enabled | boolean | false | 是否启用 Swagger/OpenAPI 生成 | | url | string | - | 文档地址(http(s)://)或本地文件路径,支持 JSON 与 YAML | | include | (string \| RegExp)[] | [] | 只处理命中的接口路径,为空表示全量 | | exclude | (string \| RegExp)[] | [] | 排除命中的接口路径(优先级高于 include) | | typeNamePrefix | string | '' | 生成根类型名的前缀 | | typeNameSuffix | string | 'Ret' | 生成根类型名的后缀 | | headers | Record<string, string> | {} | 拉取远程文档时携带的请求头(如鉴权 Token) |

capture 响应捕获

| 配置项 | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | enabled | boolean | false | 是否初始开启采集(默认关闭,需运行时手动开启) | | include | (string \| RegExp)[] | [] | 需要采集的接口路径,为空表示全量 | | exclude | (string \| RegExp)[] | [] | 排除采集的接口路径 | | overwrite | boolean | false | 已采集过的接口是否允许覆盖重新生成 | | collectPath | string | /__api-types-gen/collect | 浏览器上报采集数据的地址 | | typeNamePrefix | string | '' | 生成根类型名的前缀 | | typeNameSuffix | string | 'Ret' | 生成根类型名的后缀 | | sampleSize | number | 50 | 数组元素采样数量,用于推断数组元素类型 |

🎨 类型生成规则

1. 根类型命名

优先使用接口的 operationId,没有 operationId 时使用「请求方法 + 路径」(路径参数 {id} 会被忽略):

| 接口 | 生成根类型 | | --- | --- | | GET /api/menu/list(operationId: getMenuList) | GetMenuListRet | | POST /users(无 operationId) | PostUsersRet | | GET /users/{id}(无 operationId) | GetUsersRet |

最终名称 = typeNamePrefix + 基础名 + typeNameSuffix,Vue / TS 文件中可直接引用。

2. 基础类型映射

| JSON Schema 类型 | TypeScript 类型 | | --- | --- | | string | string | | number / integer | number | | boolean | boolean | | null | null | | object(有 properties) | 递归拆分为独立 interface | | array | T[](元素为对象时单独成类型) | | 未声明类型 / 空对象 | Record<string, unknown> / unknown |

3. 嵌套与复杂结构

  • 嵌套对象 / 数组元素对象会被拆分为独立 interface,支持单独引用;
  • 子类型名取自字段名(PascalCase),数组字段自动单数化(list → List、children → Child);
  • enum 生成字面量联合类型,如 export type Statu = 0 | 1;
  • oneOf / anyOf 生成联合类型,成员按 XxxItem1、XxxItem2 命名;
  • allOf 会合并为一个对象类型;
  • 结构完全相同的 schema 只定义一次,重复出现时复用同一类型。

4. 请求体类型

请求体为对象类结构时(OpenAPI 3 的 requestBody 或 Swagger 2 的 parameters[in=body])会额外生成请求体类型, 根名称为「基础名 + Req」,并与该接口的响应类型写在同一个文件中:

// create-user-ret.ts
export interface User { /* ... */ }
export interface CreateUserRet { code?: number; data?: User }
export type Statu = 0 | 1
export interface CreateUserReq {
  username: string
  email: string
  password: string
  age?: number
  status?: Statu
}

📁 输出产物

per-api(默认)

每个接口一个文件,文件名由根类型名转为 kebab-case,并在 outDir/index.ts 生成聚合导出:

src/api-types/
├── get-menu-list-ret.ts   # export interface MenuTreeNode / GetMenuListRet
├── get-user-info-ret.ts   # export interface UserInfo / GetUserInfoRet
├── login-ret.ts           # import type { UserInfo } from './get-user-info-ret'
└── index.ts               # export type { ... } from './xxx'

同一个接口的响应与请求体类型会写在同一个文件里,可直接被 .vue 文件 import type 引用。 若某个接口没有可生成的类型,则不会产生对应文件。

single

所有类型汇总写入 outDir/api-types.ts,按类型名去重追加,不会重复定义。

🛰️ 响应自动捕获

在配置中写了 capture 字段后,插件会在 dev 环境 注入采集脚本(默认不采集,不会每次请求都生成类型)。 脚本会拦截 fetch 与 XMLHttpRequest,克隆响应并解析 JSON,不影响原请求。

apiTypesGen({
  capture: {
    enabled: false,   // 默认关闭:需运行时手动开启
    include: ['/api'],// 只采集 /api 开头的接口
    overwrite: false, // 同一接口只生成一次
  },
})

运行时在浏览器控制台手动控制:

window.__API_TYPES_GEN__.enable()    // 开启采集
// 触发需要生成类型的接口(每个接口默认只采集一次)
window.__API_TYPES_GEN__.status()    // 当前是否开启
window.__API_TYPES_GEN__.captured()  // 查看已采集的接口列表
window.__API_TYPES_GEN__.disable()   // 关闭采集
window.__API_TYPES_GEN__.reset()     // 清空记录,允许重新采集

采集到响应后会写入 outDir 并自动刷新页面。若希望换一个接口重新采集,先调用 reset() 再重新请求即可。

⚠️ 暂不支持流式接口

当前版本不支持流式(Streaming)接口的类型生成,包括:

  • 响应采集侧:SSE(text/event-stream)以及基于 ReadableStream 的分块响应(如大模型 Chat Completions 流式返回)无法被解析,因为采集依赖克隆响应体并整体 JSON.parse,分块内容并非完整 JSON,这类接口会被自动跳过;
  • 文档侧:Swagger/OpenAPI 中把响应声明为 text/event-stream 等非 JSON 媒体类型的接口,不参与类型生成。

也就是说,POST /api/paas/v4/chat/completions 这类流式接口不会生成类型文件(而非生成空文件)。后续版本会评估支持,届时可参考文档或采集到的**非流式(stream: false)**响应作为替代方案。

🚫 过滤接口示例

include / exclude 支持字符串包含匹配,也支持正则:

apiTypesGen({
  swagger: {
    enabled: true,
    url: 'http://localhost:8080/v3/api-docs',
    include: ['/api/'],                 // 只处理 /api/ 下的接口
    exclude: [/\/actuator/, /\/internal/], // 排除监控与内部接口
  },
  capture: {
    include: [/^\/api\//],
    exclude: ['/api/health', '/api/metrics'],
  },
})

🧩 在 Vue 中使用

<script setup lang="ts">
// 从聚合入口统一引用
import type { MenuTreeNode, GetMenuListRet } from '@/api-types'
// 也可按接口文件单独引用
import type { GetMenuListRet } from '@/api-types/get-menu-list-ret'

const list = ref<MenuTreeNode[]>([])
const data = ref<GetMenuListRet>()
</script>

需要 @ 别名指向 src,例如 resolve.alias: { '@': fileURLToPath(new URL('./src', import.meta.url)) }。

🛠️ 常见问题

1. 类型没有生成?

  • 检查 swagger.enabled 是否为 true、url 是否正确;
  • 本地文件路径相对于项目根目录;YAML 与 JSON 均支持;
  • 确认接口没有被 include / exclude 过滤掉;
  • 若在构建阶段也需要生成,请设置 runOnBuild: true。

2. 生成后类型提示不生效?

  • 执行 VS Code 命令 TypeScript: Restart TS Server(Ctrl+Shift+P);
  • 确认 tsconfig.json 的 include 覆盖了 outDir 目录;
  • 打开生成的 *.ts 文件确认类型已正确写入。

3. 采集没有生效?

  • capture.enabled 默认是 false,需要在浏览器控制台调用 window.__API_TYPES_GEN__.enable();
  • 确认请求路径命中 capture.include 且未被 capture.exclude 排除;
  • 同一接口默认只采集一次,重新采集请先 reset()。

4. per-api 模式下某个文件被删除了?

该接口没有生成任何类型(例如 204 No Content、响应与请求体都没有结构),属于预期行为,不会保留空文件。

5. 流式接口为什么没有生成类型?

流式(Streaming)接口暂不支持:SSE / text/event-stream / ReadableStream 分块响应无法被整体解析为 JSON,因此不会生成类型文件。 可改用该接口的**非流式(stream: false)**响应,或直接依据 Swagger/OpenAPI 文档生成。

📋 兼容性

  • Vite 版本:^4.0.0 || ^5.0.0 || ^6.0.0
  • Swagger / OpenAPI:Swagger 2.0 与 OpenAPI 3.x 的常见结构($ref / allOf / oneOf / anyOf / enum)
  • Node 版本:Node 16+
  • 暂不支持:流式接口(SSE / text/event-stream / 分块 ReadableStream 响应)的类型生成

📄 许可证

MIT License

✨ 最佳实践

  1. 捕获模式仅在开发环境临时开启,生成完成后建议关闭;
  2. 以 Swagger/OpenAPI 文档为主数据源,捕获模式用于文档缺失或字段不准的接口兜底;
  3. 生成的类型文件可提交到代码仓库,供团队共享;
  4. 配置 recursiveKeys 以匹配后端真实的树形字段名,避免树形结构生成错误;
  5. 使用 exclude 过滤掉监控、健康检查等无意义的接口。