TypeScript Code Generation

Generate type-safe TypeScript code with full type definitions and modern async/await patterns.

Overview

Circuitry generates TypeScript code that:

  • Includes comprehensive type definitions
  • Uses modern ES6+ features with types
  • Provides interface definitions for data flow
  • Supports strict mode compilation
  • Works with popular TypeScript frameworks

Generated Code Structure

import { httpRequest, HttpOptions } from 'circuitry-helpers';
import { confirmAction, ConfirmResult } from 'circuitry-ui';

interface WorkflowData {
  [key: string]: any;
  confirmed?: boolean;
  status?: string;
}

async function workflowName(input: WorkflowData = {}): Promise<WorkflowData> {
  let data: WorkflowData = input;
  
  try {
    // Each node transforms data with type safety
    data = await httpRequest('https://api.example.com', {
      method: 'GET'
    } as HttpOptions);
    
    // Type-safe condition checking
    if (data.confirmed === true) {
      data = await processBranch(data);
    }
    
    return data;
  } catch (error) {
    console.error('Workflow error:', error);
    throw error;
  }
}

Type Definitions

Install Type Definitions

# TypeScript helper files include .d.ts definitions
# Download from Code Generation dialog:
# - circuitry-helpers.d.ts
# - circuitry-ui.d.ts

Core Types

// WorkflowData - Main data flow type
interface WorkflowData {
  [key: string]: any;
}

// HTTP Options
interface HttpOptions {
  method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
  headers?: Record<string, string>;
  body?: any;
  timeout?: number;
}

// Confirmation Result
interface ConfirmResult {
  confirmed: boolean;
  timestamp: string;
  context?: any;
}

// Message Result
interface MessageResult {
  acknowledged: boolean;
  timestamp: string;
  message: string;
  type: 'info' | 'success' | 'warning' | 'error';
}

// Form Field
interface FormField {
  name: string;
  label?: string;
  type?: 'text' | 'number' | 'email' | 'checkbox' | 'select';
  required?: boolean;
  defaultValue?: any;
  options?: Array<{ value: string; label: string }>;
}

Helper Functions with Types

HTTP Requests

const response: WorkflowData = await httpRequest(
  'https://api.example.com/users',
  {
    method: 'POST',
    headers: { 'Authorization': 'Bearer token' },
    body: { name: 'John', email: 'john@example.com' }
  }
);

User Interactions

// Confirmation with typed result
const confirm: ConfirmResult = await confirmAction('Continue?');
if (confirm.confirmed) {
  // Type-safe access
}

// Form input with typed fields
const fields: FormField[] = [
  { name: 'email', type: 'email', required: true },
  { name: 'age', type: 'number' }
];
const formData = await getFormInput(fields);

Configuration

tsconfig.json

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "lib": ["ES2020", "DOM"],
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true,
    "outDir": "./dist"
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}

Running TypeScript Workflows

Direct Execution with tsx

# Install tsx globally
npm install -g tsx

# Run TypeScript directly
tsx workflow.ts

Compile and Run

# Compile to JavaScript
tsc workflow.ts

# Run compiled JavaScript
node workflow.js

With Node.js and ts-node

# Install dependencies
npm install -D typescript ts-node @types/node

# Run with ts-node
npx ts-node workflow.ts

Framework Integration

Next.js

// app/api/workflow/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { myWorkflow } from '@/lib/workflow';

export async function POST(request: NextRequest) {
  try {
    const input = await request.json();
    const result = await myWorkflow(input);
    return NextResponse.json(result);
  } catch (error) {
    return NextResponse.json(
      { error: error.message },
      { status: 500 }
    );
  }
}

Express with TypeScript

import express, { Request, Response } from 'express';
import { myWorkflow } from './workflow';

const app = express();
app.use(express.json());

app.post('/workflow', async (req: Request, res: Response) => {
  try {
    const result = await myWorkflow(req.body);
    res.json(result);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

app.listen(3000);

Advanced Types

Custom Workflow Types

// Define specific types for your workflow
interface UserData extends WorkflowData {
  userId: string;
  email: string;
  status: 'active' | 'inactive' | 'pending';
  metadata?: {
    lastLogin: Date;
    preferences: Record<string, any>;
  };
}

async function userWorkflow(input: Partial<UserData> = {}): Promise<UserData> {
  let data: UserData = {
    userId: '',
    email: '',
    status: 'pending',
    ...input
  };
  
  // Type-safe operations
  if (data.status === 'active') {
    // TypeScript knows status is 'active' here
  }
  
  return data;
}

Generic Workflow Functions

// Create reusable typed workflow functions
async function processWorkflow<T extends WorkflowData>(
  input: T,
  processor: (data: T) => Promise<T>
): Promise<T> {
  try {
    const processed = await processor(input);
    return processed;
  } catch (error) {
    console.error('Processing failed:', error);
    throw error;
  }
}

// Usage
const result = await processWorkflow(
  { userId: '123' },
  async (data) => {
    // Process data
    return { ...data, processed: true };
  }
);

Type Guards

// Type guard functions for runtime validation
function isConfirmResult(data: any): data is ConfirmResult {
  return data && 
    typeof data.confirmed === 'boolean' &&
    typeof data.timestamp === 'string';
}

// Usage in workflow
const result = await someOperation();
if (isConfirmResult(result)) {
  // TypeScript knows result is ConfirmResult here
  if (result.confirmed) {
    // Continue processing
  }
}

Error Handling with Types

// Custom error types
class WorkflowError extends Error {
  constructor(
    message: string,
    public code: string,
    public details?: any
  ) {
    super(message);
    this.name = 'WorkflowError';
  }
}

// Typed error handling
async function safeWorkflow(input: WorkflowData): Promise<WorkflowData> {
  try {
    return await myWorkflow(input);
  } catch (error) {
    if (error instanceof WorkflowError) {
      console.error(`Workflow error ${error.code}: ${error.message}`);
      // Handle specific workflow errors
    } else if (error instanceof Error) {
      console.error('General error:', error.message);
    } else {
      console.error('Unknown error:', error);
    }
    throw error;
  }
}

Testing with TypeScript

// workflow.test.ts
import { describe, it, expect } from '@jest/globals';
import { myWorkflow } from './workflow';

describe('Workflow Tests', () => {
  it('should process valid input', async () => {
    const input: WorkflowData = {
      userId: '123',
      action: 'process'
    };
    
    const result = await myWorkflow(input);
    
    expect(result).toHaveProperty('status');
    expect(result.status).toBe('success');
  });
  
  it('should handle errors gracefully', async () => {
    const input: WorkflowData = {
      invalid: true
    };
    
    await expect(myWorkflow(input)).rejects.toThrow();
  });
});

Best Practices

  1. Strict Mode: Always enable strict mode in tsconfig.json
  2. Type Everything: Avoid using 'any' type when possible
  3. Interfaces: Define interfaces for complex data structures
  4. Type Guards: Use type guards for runtime validation
  5. Error Types: Create custom error classes for better error handling