mcpField
O
openapi-to-typescript

openapi-to-typescript

github.com/davila7开发33.1k211 次安装1 天前更新
代码仓库

关于 openapi-to-typescript

面向 TypeScript 开发者的技能,可将 OpenAPI 3.0 规范转换为接口和类型守卫。它从 schemas 与 paths 提取模型及端点类型,并在写入前验证规范。

主要功能

  1. 01读取并验证 OpenAPI 3.0 文件
  2. 02生成接口与请求响应类型
  3. 03生成类型守卫
  4. 04映射枚举、联合与交叉类型
  5. 05解析组件模式引用

适用场景

  1. 01从 API 规范生成 TypeScript 类型
  2. 02为端点定义请求和响应类型
  3. 03为运行时数据添加类型守卫
  4. 04在生成前检查规范版本与结构

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/davila7/claude-code-templates --skill openapi-to-typescript

安装后在 Claude Code 中输入/openapi-to-typescript确认已加载。

附带文件README.md

详细介绍

OpenAPI 转 TypeScript

将 OpenAPI 3.0 规范转换为 TypeScript 接口和类型守卫。

输入: OpenAPI 文件(JSON 或 YAML) 输出: 包含接口和类型守卫的 TypeScript 文件

适用场景

  • “根据 OpenAPI 生成类型”
  • “将 OpenAPI 转换为 TypeScript”
  • “创建 API 接口”
  • “根据规范生成类型”

工作流

  1. 请求 OpenAPI 文件路径(如未提供)
  2. 读取并验证文件(必须为 OpenAPI 3.0.x)
  3. 从 components/schemas 提取架构
  4. 从 paths 提取端点(请求/响应类型)
  5. 生成 TypeScript(接口 + 类型守卫)
  6. 询问保存位置(默认:当前目录下的 types/api.ts)
  7. 写入文件

OpenAPI 验证

处理前检查:

- Field "openapi" must exist and start with "3.0"
- Field "paths" must exist
- Field "components.schemas" must exist (if there are types)

如果无效,报告错误并停止。

类型映射

基本类型
OpenAPITypeScript
stringstring
numbernumber
integernumber
booleanboolean
nullnull
格式修饰符
格式TypeScript
uuidstring(注释 UUID)
datestring(注释日期)
date-timestring(注释 ISO)
emailstring(注释电子邮件)
uristring(注释 URI)
复杂类型

对象:

// OpenAPI: type: object, properties: {id, name}, required: [id]
interface Example {
  id: string;      // required: no ?
  name?: string;   // optional: with ?
}

数组:

// OpenAPI: type: array, items: {type: string}
type Names = string[];

枚举:

// OpenAPI: type: string, enum: [active, draft]
type Status = "active" | "draft";

oneOf(联合类型):

// OpenAPI: oneOf: [{$ref: Cat}, {$ref: Dog}]
type Pet = Cat | Dog;

allOf(交叉类型/继承):

// OpenAPI: allOf: [{$ref: Base}, {type: object, properties: ...}]
interface Extended extends Base {
  extraField: string;
}

代码生成

文件头部
/**
 * Auto-generated from: {source_file}
 * Generated at: {timestamp}
 *
 * DO NOT EDIT MANUALLY - Regenerate from OpenAPI schema
 */
接口(来自 components/schemas)

对于 components/schemas 中的每个架构:

export interface Product {
  /** Product unique identifier */
  id: string;

  /** Product title */
  title: string;

  /** Product price */
  price: number;

  /** Created timestamp */
  created_at?: string;
}
  • 将 OpenAPI 描述用作 JSDoc
  • required[] 中的字段不加 ?
  • 不在 required[] 中的字段加 ?
请求/响应类型(来自 paths)

对于 paths 中的每个端点:

// GET /products - query params
export interface GetProductsRequest {
  page?: number;
  limit?: number;
}

// GET /products - response 200
export type GetProductsResponse = ProductList;

// POST /products - request body
export interface CreateProductRequest {
  title: string;
  price: number;
}

// POST /products - response 201
export type CreateProductResponse = Product;

命名约定:

  • 参数/请求体使用 {Method}{Path}Request
  • 响应使用 {Method}{Path}Response
类型守卫

为每个主要接口生成类型守卫:

export function isProduct(value: unknown): value is Product {
  return (
    typeof value === 'object' &&
    value !== null &&
    'id' in value &&
    typeof (value as any).id === 'string' &&
    'title' in value &&
    typeof (value as any).title === 'string' &&
    'price' in value &&
    typeof (value as any).price === 'number'
  );
}

类型守卫规则:

  • 检查 typeof value === 'object' && value !== null
  • 对每个必需字段:检查 'field' in value
  • 对基本类型字段:检查 typeof
  • 对数组:检查 Array.isArray()
  • 对枚举:检查 .includes()
错误类型(始终包含)
export interface ApiError {
  status: number;
  error: string;
  detail?: string;
}

export function isApiError(value: unknown): value is ApiError {
  return (
    typeof value === 'object' &&
    value !== null &&
    'status' in value &&
    typeof (value as any).status === 'number' &&
    'error' in value &&
    typeof (value as any).error === 'string'
  );
}

$ref 解析

遇到 {"$ref": "#/components/schemas/Product"} 时:

  1. 提取架构名称(Product)
  2. 直接使用该类型(不要内联解析)
// OpenAPI: items: {$ref: "#/components/schemas/Product"}
// TypeScript:
items: Product[]  // reference, not inline

完整示例

输入(OpenAPI):

{
  "openapi": "3.0.0",
  "components": {
    "schemas": {
      "User": {
        "type": "object",
        "properties": {
          "id": {"type": "string", "format": "uuid"},
          "email": {"type": "string", "format": "email"},
          "role": {"type": "string", "enum": ["admin", "user"]}
        },
        "required": ["id", "email", "role"]
      }
    }
  },
  "paths": {
    "/users/{id}": {
      "get": {
        "parameters": [{"name": "id", "in": "path", "required": true}],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {"$ref": "#/components/schemas/User"}
              }
            }
          }
        }
      }
    }
  }
}

输出(TypeScript):

/**
 * Auto-generated from: api.openapi.json
 * Generated at: 2025-01-15T10:30:00Z
 *
 * DO NOT EDIT MANUALLY - Regenerate from OpenAPI schema
 */

// ============================================================================
// Types
// ============================================================================

export type UserRole = "admin" | "user";

export interface User {
  /** UUID */
  id: string;

  /** Email */
  email: string;

  role: UserRole;
}

// ============================================================================
// Request/Response Types
// ============================================================================

export interface GetUserByIdRequest {
  id: string;
}

export type GetUserByIdResponse = User;

// ============================================================================
// Type Guards
// ============================================================================

export function isUser(value: unknown): value is User {
  return (
    typeof value === 'object' &&
    value !== null &&
    'id' in value &&
    typeof (value as any).id === 'string' &&
    'email' in value &&
    typeof (value as any).email === 'string' &&
    'role' in value &&
    ['admin', 'user'].includes((value as any).role)
  );
}

// ============================================================================
// Error Types
// ============================================================================

export interface ApiError {
  status: number;
  error: string;
  detail?: string;
}

export function isApiError(value: unknown): value is ApiError {
  return (
    typeof value === 'object' &&
    value !== null &&
    'status' in value &&
    typeof (value as any).status === 'number' &&
    'error' in value &&
    typeof (value as any).error === 'string'
  );
}

常见错误

错误处理方式
OpenAPI 版本 != 3.0.x报告仅支持 3.0
未找到 $ref列出缺失的引用
未知类型使用 unknown 并发出警告
循环引用使用带延迟引用的类型别名

评论

支持 Markdown