openapi-typescript-codegen
@hey-api/openapi-ts 是 openapi-typescript-codegen 的活跃维护分支,支持从 OpenAPI/Swagger 文档生成 TypeScript 类型定义和 API 客户端代码
工具说明
与 openapi-typescript-codegen 的关系
openapi-typescript-codegen 项目已不再维护,官方建议迁移到 @hey-api/openapi-ts,这是原项目的活跃分支,修复了原项目的问题并持续更新。
核心特性
- 灵活配置:可以只生成类型,也可以生成服务代码
- 类型安全:完整的 TypeScript 类型定义
- 支持 Swagger 2.0:通过
swagger2openapi转换后支持
限制说明
- 不支持按 tags 分割:
@hey-api/openapi-ts不支持按 OpenAPI tags 自动分割生成多个文件,所有类型定义会生成在单个文件中(types.gen.ts) - 如需按 tags 分割:可以考虑使用
openapi-generator-cli,它支持按 schema 分割生成多个文件(models/目录)
安装
建议在docker容器中运行,避免本地环境依赖复杂
npm install -D @hey-api/openapi-ts
使用方式
后端 Makefile 配置
FRONT_TYPES_DIR ?= ./frontend-types
generate-front-types: swagger ## 生成前端TypeScript类型定义(多文件)
@echo "generating frontend types to $(FRONT_TYPES_DIR)..."
@mkdir -p $(FRONT_TYPES_DIR)
docker run --rm \
-v $(PWD)/docs/swagger.yaml:/swagger.yaml:ro \
-v $(PWD)/$(FRONT_TYPES_DIR):/output \
node:18-alpine sh -c "\
npm install -g swagger2openapi @hey-api/openapi-ts && \
swagger2openapi /swagger.yaml -o /output/openapi3.yaml && \
openapi-ts --input /output/openapi3.yaml --output /output --types --schemas"
@echo "Frontend types generated to $(FRONT_TYPES_DIR)"
配置文件方式
创建 openapi-ts.config.ts:
export default {
input: 'docs/swagger.yaml',
output: {
path: 'src/api/types',
},
client: {
// 不生成服务代码,只生成类型
enabled: false,
},
types: {
// 生成类型定义
enabled: true,
},
schemas: {
// 生成 schema 类型
enabled: true,
},
};
生成结果
生成的文件结构:
frontend-types/
├── types.gen.ts # 所有类型定义(单个文件)
├── schemas/ # Schema 类型(如果启用)
├── client/ # 客户端代码(如果启用)
│ ├── client.gen.ts
│ └── ...
├── core/ # 核心工具代码(如果启用)
│ └── ...
├── sdk.gen.ts # SDK 方法(如果启用)
└── index.ts # 统一导出
注意:如果只生成类型(client: { enabled: false }),主要文件是 types.gen.ts,包含所有类型定义。
生成文件示例
types.gen.ts(类型定义文件):
export interface UserInfo {
uid: number;
username: string;
email: string;
role: string;
}
export interface LoginRequest {
username: string;
password: string;
login_type: string;
}
export interface LoginResponse {
code: number;
msg: string;
data: {
token: string;
uid: number;
expire_at: number;
};
}
sdk.gen.ts(如果启用客户端代码生成):
import type { UserInfo, LoginRequest, LoginResponse } from './types.gen';
export const getApiV1UserInfo = (options: Options<GetApiV1UserInfoData>) => {
return client.get<GetApiV1UserInfoResponses>({
url: '/api/v1/user/info',
...options
});
};
export const postApiV1Login = (options: Options<PostApiV1LoginData>) => {
return client.post<PostApiV1LoginResponses>({
url: '/api/v1/login',
...options
});
};
前端集成
复制生成的代码
将后端项目的 frontend-types/ 目录复制到前端项目的 src/api/types/ 目录。
使用生成的类型
import type { UserInfo, LoginRequest, LoginResponse } from '@/api/types/types.gen';
// 自行封装 API 调用
export async function getUserInfo(uid: number): Promise<UserInfo> {
const response = await axios.get(`/api/v1/user/info?uid=${uid}`);
return response.data.data;
}
export async function login(request: LoginRequest): Promise<LoginResponse> {
const response = await axios.post('/api/v1/login', request);
return response.data;
}
使用生成的 SDK(如果启用客户端代码)
import { getApiV1UserInfo, postApiV1Login } from '@/api/types/sdk.gen';
import type { GetApiV1UserInfoData, PostApiV1LoginData } from '@/api/types/types.gen';
// 使用生成的 SDK 方法
const userInfo = await getApiV1UserInfo({ params: { uid: 123 } });
const loginResult = await postApiV1Login({ body: { username: 'admin', password: '123456' } });
配置选项
命令行参数
openapi-ts --input swagger.yaml --output ./output \
--types \ # 生成类型定义
--schemas \ # 生成 schema 类型
--client \ # 生成客户端代码
--services # 生成服务类
配置文件选项
export default {
input: 'docs/swagger.yaml',
output: {
path: 'src/api/types',
},
client: {
enabled: true, // 是否生成客户端代码
name: 'ApiClient', // 客户端类名
},
services: {
enabled: true, // 是否生成服务类
},
types: {
enabled: true, // 是否生成类型定义
},
schemas: {
enabled: true, // 是否生成 schema 类型
},
};
最佳实践
只生成类型定义
如果只需要类型定义,配置 client: { enabled: false }:
export default defineConfig({
input: './docs/swagger.yaml',
output: {
path: './account-types',
},
client: {
enabled: false, // 不生成客户端代码
},
types: {
enabled: true, // 只生成类型定义
},
});
生成后只保留 types.gen.ts 文件,删除其他文件。
类型导入规范
// ✅ 推荐:从 types.gen.ts 导入需要的类型
import type { UserInfo, LoginRequest, LoginResponse } from '@/api/types/types.gen';
// ❌ 不推荐:导入所有类型
import type * as Types from '@/api/types/types.gen';
与现有代码集成
如果项目已有手动封装的 API,可以保持原有接口不变,内部使用生成的类型:
// 使用生成的类型
import type { UserInfo } from '@/api/types/types.gen';
// 保持原有的 API 封装
export async function getUserInfo(uid: number): Promise<UserInfo> {
const response = await axios.get(`/api/v1/user/info?uid=${uid}`);
return response.data.data;
}
优势
- 灵活配置:可以只生成类型,也可以生成完整服务
- 类型安全:完整的 TypeScript 类型支持
- 活跃维护:持续更新,修复问题及时
- 轻量级:只生成类型时,输出文件简洁
常见问题
Swagger 2.0 支持
@hey-api/openapi-ts 需要 OpenAPI 3.x,如果后端使用 swaggo/swag 生成 Swagger 2.0,需要先使用 swagger2openapi 转换。
文件分割限制
重要:@hey-api/openapi-ts 不支持按 OpenAPI tags 分割生成多个文件。所有类型定义会生成在单个 types.gen.ts 文件中。
如果需要按模块分割类型文件,可以考虑:
- 使用
openapi-generator-cli,它支持按 schema 分割(models/目录) - 使用自定义脚本后处理,按 tags 分割
types.gen.ts文件
与现有代码集成
如果项目已有手动封装的 API,可以保持原有接口不变,内部使用生成的类型,实现渐进式迁移。