openapi-to-typescript
Install this skill
npx skills add softaworks/agent-toolkitWorks across Claude Code, Cursor, Codex, Copilot & Antigravity
The openapi-to-typescript skill automates the translation of OpenAPI 3.0 specifications into strictly typed TypeScript interfaces and runtime type guards. By parsing JSON or YAML files, it extracts schema definitions from components and maps path-based request and response objects into clean, maintainable code. It handles complex OpenAPI patterns including enums, unions (oneOf), and intersections (allOf), ensuring that generated types accurately reflect the API contract. The tool enforces type safety by creating guard functions that validate data at runtime, verifying field existence and primitive types against the original specification. It preserves documentation by converting OpenAPI descriptions into JSDoc comments, resulting in code that is both type-safe and self-documenting for frontend or backend development teams.
When to Use This Skill
- •Synchronizing frontend types with backend API changes
- •Implementing type-safe fetch or Axios wrappers
- •Bootstrapping internal SDKs from an existing Swagger definition
- •Validating incoming API payloads against schema definitions
How to Invoke This Skill
Example prompts that trigger this skill in Claude Code, Cursor, or Antigravity:
- “generate types from my openapi.yaml
- “create typescript interfaces from this api spec
- “convert openapi definition to ts types
- “generate type guards for my openapi file
- “sync types from api.json
Pro Tips
- 💡Always keep your OpenAPI specification up-to-date to ensure the generated TypeScript types accurately reflect your API's current state.
- 💡Combine this skill with a code generation skill to scaffold not just types, but also full API client boilerplate.
- 💡Leverage the generated type guards for robust runtime validation of data received from your API endpoints, enhancing application resilience.
What this skill does
- •Converts components/schemas into exported TypeScript interfaces
- •Generates runtime type guard functions for API responses
- •Maps standard OpenAPI formats like UUID and ISO date to typed comments
- •Resolves internal references ($ref) as named types rather than inlining
- •Creates boilerplate-free request and response types for all API paths
When not to use it
- ✕When working with OpenAPI 2.0 (Swagger) specifications
- ✕When you require complex client-side code generation, such as full HTTP request methods
- ✕If the source OpenAPI file is fragmented across multiple external files
Example workflow
- Provide the path to the OpenAPI YAML or JSON file
- Verify the spec meets the 3.0.x structural requirements
- Trigger the generation process to parse schemas and paths
- Specify the target output directory for the generated file
- Review the resulting interfaces and runtime guards in types/api.ts
Prerequisites
- –An OpenAPI 3.0.x compliant specification file
- –A TypeScript-based project structure
Pitfalls & limitations
- !Requires strict adherence to OpenAPI 3.0 format; 2.0 or 3.1 files will cause failures
- !Runtime type guards only perform shallow validation and may not catch deeply nested object property mismatches
- !Manual edits to the generated file are lost upon re-generation
FAQ
How it compares
Unlike manual definition or generic prompting which often results in type drift, this skill produces deterministic, standardized code that automatically keeps validation guards in sync with the source spec.
📄 Full skill instructions — original source: softaworks/agent-toolkit
Converts OpenAPI 3.0 specifications to TypeScript interfaces and type guards.
**Input:** OpenAPI file (JSON or YAML)
**Output:** TypeScript file with interfaces and type guards
## When to Use
- "generate types from openapi"
- "convert openapi to typescript"
- "create API interfaces"
- "generate types from spec"
## Workflow
1. Request the OpenAPI file path (if not provided)
2. Read and validate the file (must be OpenAPI 3.0.x)
3. Extract schemas from
components/schemas4. Extract endpoints from
paths (request/response types)5. Generate TypeScript (interfaces + type guards)
6. Ask where to save (default:
types/api.ts in current directory)7. Write the file
## OpenAPI Validation
Check before processing:
- Field "openapi" must exist and start with "3.0"
- Field "paths" must exist
- Field "components.schemas" must exist (if there are types)If invalid, report the error and stop.
## Type Mapping
### Primitives
| OpenAPI | TypeScript |
|-------------|--------------|
|
string | string ||
number | number ||
integer | number ||
boolean | boolean ||
null | null |### Format Modifiers
| Format | TypeScript |
|---------------|-------------------------|
|
uuid | string (comment UUID) ||
date | string (comment date) ||
date-time | string (comment ISO) ||
email | string (comment email)||
uri | string (comment URI) |### Complex Types
**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;
}## Code Generation
### File Header
/**
* Auto-generated from: {source_file}
* Generated at: {timestamp}
*
* DO NOT EDIT MANUALLY - Regenerate from OpenAPI schema
*/### Interfaces (from components/schemas)
For each schema in
components/schemas:export interface Product {
/** Product unique identifier */
id: string;
/** Product title */
title: string;
/** Product price */
price: number;
/** Created timestamp */
created_at?: string;
}- Use OpenAPI description as JSDoc
- Fields in
required[] have no ?- Fields outside
required[] have ?### Request/Response Types (from paths)
For each endpoint in
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;Naming convention:
-
{Method}{Path}Request for params/body-
{Method}{Path}Response for response### Type Guards
For each main interface, generate a type guard:
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'
);
}Type guard rules:
- Check
typeof value === 'object' && value !== null- For each required field: check
'field' in value- For primitive fields: check
typeof- For arrays: check
Array.isArray()- For enums: check
.includes()### Error Type (always include)
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 Resolution
When encountering
{"$ref": "#/components/schemas/Product"}:1. Extract the schema name (
Product)2. Use the type directly (don't resolve inline)
// OpenAPI: items: {$ref: "#/components/schemas/Product"}
// TypeScript:
items: Product[] // reference, not inline## Complete Example
**Input (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"}
}
}
}
}
}
}
}
}**Output (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'
);
}## Common Errors
| 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 |
How to Use This Skill Unit
Option A: Project-Specific (Recommended)
- Click "Download" above
- In your project, create the directory:
.agent/skills/openapi-to-typescript/ - Save the file as
SKILL.md - The agent will automatically discover the skill based on its description.
Option B: Global Installation (All Agents)
Save the file to these locations to make it available across all projects:
- Claude Code:
~/.claude/skills/softaworks/agent-toolkit/openapi-to-typescript/SKILL.md - Cursor:
~/.cursor/skills/softaworks/agent-toolkit/openapi-to-typescript/SKILL.md - Antigravity:
~/.gemini/antigravity/skills/softaworks/agent-toolkit/openapi-to-typescript/SKILL.md
🚀 Install with CLI:npx skills add softaworks/agent-toolkit
