openapi-to-typescript について
開発者向けのスキルで、OpenAPI 3.0仕様からTypeScriptのインターフェース、リクエスト・レスポンス型、型ガードを生成します。仕様の検証と参照の処理にも対応します。
主な機能
- 01OpenAPI 3.0仕様の検証
- 02スキーマからのインターフェース生成
- 03エンドポイントのリクエスト・レスポンス型
- 04型ガードの生成
- 05$refの処理とエラー報告
活用シーン
- 01API仕様からTypeScript型を生成
- 02エンドポイントの入出力定義を作成
- 03変換前にOpenAPIファイルを検証
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ softaworks/ agent-toolkit --skill openapi-to-typescriptインストール後、Claude Code で/openapi-to-typescriptを入力して読み込まれたか確認します。
同梱ファイルREADME.md
詳細
OpenAPI から TypeScript
OpenAPI 3.0 の仕様を TypeScript のインターフェースと型ガードに変換します。
入力: OpenAPI ファイル(JSON または YAML) 出力: インターフェースと型ガードを含む TypeScript ファイル
使用するタイミング
- "generate types from openapi"
- "convert openapi to typescript"
- "create API interfaces"
- "generate types from spec"
ワークフロー
- OpenAPI ファイルのパスを尋ねる(指定されていない場合)
- ファイルを読み込んで検証する(OpenAPI 3.0.x である必要があります)
components/schemasからスキーマを抽出するpathsからエンドポイントを抽出する(リクエスト/レスポンスの型)- TypeScript を生成する(インターフェース + 型ガード)
- 保存先を尋ねる(デフォルト: カレントディレクトリの
types/api.ts) - ファイルを書き込む
OpenAPI の検証
処理の前に次を確認します:
- Field "openapi" must exist and start with "3.0"
- Field "paths" must exist
- Field "components.schemas" must exist (if there are types)
無効な場合は、エラーを報告して停止します。
型のマッピング
プリミティブ
| OpenAPI | TypeScript |
|---|---|
string | string |
number | number |
integer | number |
boolean | boolean |
null | null |
フォーマット修飾子
| Format | TypeScript |
|---|---|
uuid | string (comment UUID) |
date | string (comment date) |
date-time | string (comment ISO) |
email | string (comment email) |
uri | string (comment URI) |
複合型
Object:
// OpenAPI: type: object, properties: {id, name}, required: [id]
interface Example {
id: string; // required: no ?
name?: string; // optional: with ?
}
Array:
// OpenAPI: type: array, items: {type: string}
type Names = string[];
Enum:
// OpenAPI: type: string, enum: [active, draft]
type Status = "active" | "draft";
oneOf (Union):
// OpenAPI: oneOf: [{$ref: Cat}, {$ref: Dog}]
type Pet = Cat | Dog;
allOf (Intersection/Extends):
// 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 の description を 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()を確認する - enum については
.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"} に遭遇した場合:
- スキーマ名(
Product)を抽出する - その型をそのまま使用する(インラインで解決しない)
// 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'
);
}
よくあるエラー
| Error | Action |
|---|---|
| OpenAPI version != 3.0.x | Report that only 3.0 is supported |
| $ref not found | List missing refs |
| Unknown type | Use unknown and warn |
| Circular reference | Use type alias with lazy reference |
コメント
Markdown 対応