Skip to content

Latest commit

 

History

History
300 lines (236 loc) · 8.08 KB

File metadata and controls

300 lines (236 loc) · 8.08 KB

OpenAPI to TypeScript

A Claude Code skill that converts OpenAPI 3.0 specifications (JSON or YAML) into TypeScript interfaces and type guards.

Purpose

This skill automates the process of generating type-safe TypeScript code from OpenAPI API specifications. It creates:

  • TypeScript interfaces for all schema definitions
  • Request/Response type definitions for API endpoints
  • Runtime type guards for validation
  • Proper handling of complex types (unions, intersections, enums, arrays)

When to Use

Use this skill when you need to:

  • Generate TypeScript types from an OpenAPI specification
  • Create type-safe API client interfaces
  • Convert API documentation into TypeScript code
  • Maintain type safety between backend API specs and frontend code

Trigger Phrases

  • "generate types from openapi"
  • "convert openapi to typescript"
  • "create API interfaces"
  • "generate types from spec"
  • "convert schema to TS"

How It Works

Workflow

  1. Request Input: Asks for the OpenAPI file path (if not provided)
  2. Validation: Reads and validates the OpenAPI specification (must be 3.0.x)
  3. Schema Extraction: Extracts schemas from components/schemas
  4. Endpoint Analysis: Extracts request/response types from paths
  5. Code Generation: Generates TypeScript interfaces and type guards
  6. Output: Asks where to save (default: types/api.ts)
  7. Write File: Creates the TypeScript file

OpenAPI Support

  • Version: OpenAPI 3.0.x only
  • Format: JSON or YAML
  • Required fields: openapi, paths, components.schemas

Key Features

Type Mapping

Primitives:

  • stringstring
  • number / integernumber
  • booleanboolean
  • nullnull

Format Modifiers (with JSDoc comments):

  • uuidstring (/** UUID */)
  • datestring (/** Date */)
  • date-timestring (/** ISO DateTime */)
  • emailstring (/** Email */)
  • uristring (/** URI */)

Complex Types:

  • Objects → TypeScript interfaces with optional/required fields
  • Arrays → TypeScript array types (Type[])
  • Enums → TypeScript union types ("value1" | "value2")
  • oneOf → Union types (Type1 | Type2)
  • allOf → Interface extension (extends)
  • $ref → Direct type references

Generated Code Structure

/**
 * Auto-generated from: {source_file}
 * Generated at: {timestamp}
 *
 * DO NOT EDIT MANUALLY - Regenerate from OpenAPI schema
 */

// Types
export interface User { ... }
export type Status = "active" | "draft";

// Request/Response Types
export interface GetUsersRequest { ... }
export type GetUsersResponse = User[];

// Type Guards
export function isUser(value: unknown): value is User { ... }

// Error Types (always included)
export interface ApiError { ... }
export function isApiError(value: unknown): value is ApiError { ... }

Type Guards

Runtime validation functions for each interface:

  • Check object structure
  • Validate required fields
  • Type-check primitives
  • Validate enums and arrays

Usage Examples

Basic Usage

User: Generate TypeScript types from my OpenAPI spec at ./api/openapi.json

Claude: I'll convert your OpenAPI specification to TypeScript.
[Reads file, validates, generates types, saves to types/api.ts]

With Custom Output Path

User: Convert openapi.yaml to TypeScript and save it to src/types/backend.ts

Claude: I'll generate TypeScript types from your OpenAPI spec.
[Generates and saves to specified location]

Example Input/Output

Input (openapi.json):

{
  "openapi": "3.0.0",
  "components": {
    "schemas": {
      "Product": {
        "type": "object",
        "properties": {
          "id": {"type": "string", "format": "uuid"},
          "name": {"type": "string"},
          "price": {"type": "number"},
          "status": {"type": "string", "enum": ["active", "draft"]}
        },
        "required": ["id", "name", "price", "status"]
      }
    }
  },
  "paths": {
    "/products": {
      "get": {
        "parameters": [
          {"name": "page", "in": "query", "schema": {"type": "integer"}},
          {"name": "limit", "in": "query", "schema": {"type": "integer"}}
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {"$ref": "#/components/schemas/Product"}
                }
              }
            }
          }
        }
      }
    }
  }
}

Output (types/api.ts):

/**
 * Auto-generated from: openapi.json
 * Generated at: 2026-01-18T19:00:00Z
 *
 * DO NOT EDIT MANUALLY - Regenerate from OpenAPI schema
 */

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

export type ProductStatus = "active" | "draft";

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

  name: string;

  price: number;

  status: ProductStatus;
}

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

export interface GetProductsRequest {
  page?: number;
  limit?: number;
}

export type GetProductsResponse = Product[];

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

export function isProduct(value: unknown): value is Product {
  return (
    typeof value === 'object' &&
    value !== null &&
    'id' in value &&
    typeof (value as any).id === 'string' &&
    'name' in value &&
    typeof (value as any).name === 'string' &&
    'price' in value &&
    typeof (value as any).price === 'number' &&
    'status' in value &&
    ['active', 'draft'].includes((value as any).status)
  );
}

// ============================================================================
// 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'
  );
}

Benefits

  • Type Safety: Catch API contract violations at compile time
  • Auto-completion: Full IDE support for API request/response types
  • Runtime Validation: Type guards for validating API responses
  • Documentation: JSDoc comments preserved from OpenAPI descriptions
  • Maintainability: Regenerate types when API spec changes
  • DRY Principle: Single source of truth (OpenAPI spec)

Limitations

  • Only supports OpenAPI 3.0.x (not 2.0 or 3.1)
  • Circular references handled with type aliases
  • Unknown types fall back to unknown with warnings
  • Complex allOf scenarios may need manual refinement

Related Tools

This skill complements:

  • openapi-validator: Validate OpenAPI specs before conversion
  • api-client-generator: Generate full API clients using these types
  • schema-diff: Compare OpenAPI versions to track type changes

Technical Details

Naming Conventions

  • Interfaces: PascalCase (e.g., User, Product)
  • Request Types: {Method}{Path}Request (e.g., GetUsersRequest)
  • Response Types: {Method}{Path}Response (e.g., GetUsersResponse)
  • Type Guards: is{TypeName} (e.g., isUser, isProduct)
  • Enums: {TypeName}{FieldName} (e.g., ProductStatus, UserRole)

Field Handling

  • Required fields: No ? suffix
  • Optional fields: ? suffix
  • Descriptions: Converted to JSDoc comments
  • Formats: Added as JSDoc comments

Error Handling

The skill validates and reports:

  • Invalid OpenAPI version
  • Missing required fields (openapi, paths, components)
  • Unresolved $ref references
  • Unknown or unsupported types
  • Circular reference warnings

License

Part of the Softaworks Agent Skills collection.