name: openapi-to-typescript description: Convert OpenAPI 3.0 JSON/YAML specifications to TypeScript interfaces and type guards. Use when generating types from an API spec, creating typed API client code, or converting OpenAPI schemas to TypeScript. Produces interfaces from components/schemas, request/response types from paths, and runtime type guards. tags: [openapi, typescript, codegen, api]
OpenAPI to TypeScript
Convert OpenAPI 3.0 specifications to TypeScript interfaces and type guards.
Input: OpenAPI file (JSON or YAML) Output: TypeScript file with interfaces, request/response types, and type guards
When to Use
- "Generate types from OpenAPI"
- "Convert OpenAPI to TypeScript"
- "Create API interfaces from spec"
- New API integration that has an OpenAPI spec
- Keeping TypeScript types in sync with backend API
Workflow
- Request OpenAPI file path (if not provided)
- Read and validate (must be OpenAPI 3.0.x)
- Extract schemas from
components/schemas - Extract endpoints from
paths(request/response types) - Generate TypeScript (interfaces + type guards)
- Ask where to save (default:
types/api.ts) - Write the file
Type Mapping
Primitives
| OpenAPI | TypeScript |
|---|---|
string |
string |
number |
number |
integer |
number |
boolean |
boolean |
null |
null |
Format Modifiers
| Format | TypeScript | Note |
|---|---|---|
uuid |
string |
Add JSDoc @format uuid |
date |
string |
Add JSDoc @format date |
date-time |
string |
Add JSDoc @format ISO 8601 |
email |
string |
Add JSDoc @format email |
uri |
string |
Add JSDoc @format URI |
Complex Types
Object with required/optional fields:
// required: [id], optional: name
interface Example {
id: string; // no ? -- required
name?: string; // ? -- optional
}
Array:
// items: {type: string}
type Names = string[];
Enum:
// enum: [active, draft]
type Status = "active" | "draft";
oneOf (Union):
// oneOf: [{$ref: Cat}, {$ref: Dog}]
type Pet = Cat | Dog;
allOf (Intersection/Extends):
// allOf: [{$ref: Base}, {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)
export interface Product {
/** Product unique identifier */
id: string;
/** Product title */
title: string;
/** Product price */
price: number;
/** Created timestamp (ISO 8601) */
created_at?: string;
}
Rules:
- Use OpenAPI
descriptionas JSDoc comment - Fields in
required[]have no? - Fields not in
required[]have?
Request/Response Types (from paths)
Naming convention: {Method}{Path}Request / {Method}{Path}Response
// 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;
Type Guards
For each main interface, generate a runtime 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 - Required fields:
'field' in value+ type check - Arrays:
Array.isArray() - Enums:
.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"}:
- Extract schema name (
Product) - Use the type directly as a reference (don't inline)
// $ref: "#/components/schemas/Product"
items: Product[] // reference, not inlined
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
* DO NOT EDIT MANUALLY
*/
export type UserRole = "admin" | "user";
export interface User {
/** @format uuid */
id: string;
/** @format email */
email: string;
role: UserRole;
}
export interface GetUserByIdRequest {
id: string;
}
export type GetUserByIdResponse = User;
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)
);
}
export interface ApiError {
status: number;
error: string;
detail?: string;
}
Error Handling
| Error | Action |
|---|---|
| OpenAPI version != 3.0.x | Report: only 3.0 supported |
Missing $ref target |
List missing refs, continue with unknown |
| Unknown type | Use unknown and warn |
| Circular reference | Use type alias with lazy reference |
No components/schemas |
Generate only path types |
Anti-Patterns
| Avoid | Why | Instead |
|---|---|---|
Inlining $ref schemas |
Duplicates types, harder to maintain | Use type references |
| Skipping optional markers | Runtime errors on missing fields | Respect required[] array |
Generating any types |
Defeats purpose of TypeScript | Use unknown with type guards |
| Manual edits to generated files | Overwritten on regeneration | Extend types in separate files |
Ignoring format hints |
Loses documentation value | Add JSDoc comments |
References
- Based on softaworks/agent-toolkit openapi-to-typescript (MIT License)
- OpenAPI 3.0 Specification