Claude Code TypeScript SDK Examples

claude-code claude-code-typescript-sdk typescript examples tutorial workshop intermediate practical real-world

A comprehensive collection of practical examples and use cases for the @anthropic-ai/claude-code TypeScript SDK and @anthropic-ai/sdk, including both basic usage examples and real-world implementations.

Table of Contents

  1. Installation & Setup
  2. Basic Usage Examples
  3. Streaming Examples
  4. React & Next.js Integration
  5. Advanced Features
  6. Practical Implementations
  7. Integration Patterns
  8. Workshop Exercise Ideas
  9. Real-World Projects
  10. Best Practices
  11. Additional Resources

Installation & Setup

Installing Claude Code CLI

# Global installation
npm install -g @anthropic-ai/claude-code
 
# Project installation
npm install @anthropic-ai/claude-code

Installing Anthropic SDK

npm install @anthropic-ai/sdk

Environment Setup

export ANTHROPIC_API_KEY='your-api-key-here'

Basic Usage Examples

1. Simple Message Creation

import Anthropic from '@anthropic-ai/sdk';
 
const client = new Anthropic({
  apiKey: process.env['ANTHROPIC_API_KEY'], // Optional if set as env variable
});
 
async function basicExample() {
  const message = await client.messages.create({
    max_tokens: 1024,
    messages: [{ role: 'user', content: 'Hello, Claude' }],
    model: 'claude-sonnet-4-20250514',
  });
  
  console.log(message.content);
}

2. Using Claude Code Programmatically

import { ClaudeCode } from '@anthropic-ai/claude-code';
 
async function generateCode() {
  const claudeCode = new ClaudeCode();
  
  const result = await claudeCode.execute({
    prompt: "Create a TypeScript function that validates email addresses",
    outputFormat: "json"
  });
  
  console.log(result);
}

3. Error Handling

import Anthropic from '@anthropic-ai/sdk';
 
const client = new Anthropic();
 
async function safeApiCall() {
  try {
    const message = await client.messages.create({
      max_tokens: 1024,
      messages: [{ role: 'user', content: 'Explain TypeScript generics' }],
      model: 'claude-sonnet-4-20250514',
    });
    return message;
  } catch (error) {
    if (error instanceof Anthropic.APIError) {
      console.error(`API Error ${error.status}:`, error.message);
      if (error.status === 429) {
        console.log('Rate limit exceeded, please retry later');
      }
    } else {
      console.error('Unexpected error:', error);
    }
  }
}

Streaming Examples

1. Basic Streaming with Async Iterator

import Anthropic from '@anthropic-ai/sdk';
 
async function streamingExample() {
  const client = new Anthropic();
  
  const stream = await client.messages.create({
    max_tokens: 1024,
    messages: [{ role: 'user', content: 'Write a story about a robot' }],
    model: 'claude-sonnet-4-20250514',
    stream: true,
  });
  
  for await (const event of stream) {
    if (event.type === 'content_block_delta') {
      process.stdout.write(event.delta.text);
    }
  }
}

2. Event-Driven Streaming

import Anthropic from '@anthropic-ai/sdk';
 
async function eventStreamExample() {
  const client = new Anthropic();
  
  const stream = client.messages
    .stream({
      messages: [{ role: 'user', content: 'Explain quantum computing' }],
      model: 'claude-sonnet-4-20250514',
      max_tokens: 1024,
    })
    .on('text', (text) => {
      process.stdout.write(text);
    })
    .on('contentBlock', (content) => {
      console.log('\n\nContent block completed:', content);
    })
    .on('message', (message) => {
      console.log('\n\nFinal message:', message);
    });
 
  // Wait for completion
  const finalMessage = await stream.finalMessage();
  return finalMessage;
}

3. Stream Management with Cancellation

import Anthropic from '@anthropic-ai/sdk';
 
async function cancellableStream() {
  const client = new Anthropic();
  
  const stream = await client.messages.create({
    max_tokens: 2048,
    messages: [{ role: 'user', content: 'Count to 100 slowly' }],
    model: 'claude-sonnet-4-20250514',
    stream: true,
  });
 
  let count = 0;
  for await (const event of stream) {
    if (event.type === 'content_block_delta') {
      console.log(event.delta.text);
      count++;
      
      // Cancel after 10 events
      if (count >= 10) {
        stream.controller.abort();
        break;
      }
    }
  }
}

1. Tool Use Example

import Anthropic from '@anthropic-ai/sdk';
 
async function toolUseExample() {
  const client = new Anthropic();
  
  const response = await client.messages.create({
    model: 'claude-sonnet-4-20250514',
    max_tokens: 1024,
    tools: [
      {
        name: 'get_weather',
        description: 'Get the current weather in a given location',
        input_schema: {
          type: 'object',
          properties: {
            location: {
              type: 'string',
              description: 'The city and state, e.g. San Francisco, CA',
            },
          },
          required: ['location'],
        },
      },
    ],
    messages: [
      {
        role: 'user',
        content: 'What\'s the weather like in San Francisco?',
      },
    ],
  });
 
  // Handle tool use in response
  for (const content of response.content) {
    if (content.type === 'tool_use') {
      console.log('Tool called:', content.name);
      console.log('With input:', content.input);
      
      // Simulate tool execution
      const toolResult = await executeWeatherTool(content.input);
      
      // Continue conversation with tool result
      const followUp = await client.messages.create({
        model: 'claude-sonnet-4-20250514',
        max_tokens: 1024,
        messages: [
          ...response.messages,
          {
            role: 'assistant',
            content: response.content,
          },
          {
            role: 'user',
            content: [
              {
                type: 'tool_result',
                tool_use_id: content.id,
                content: JSON.stringify(toolResult),
              },
            ],
          },
        ],
      });
    }
  }
}
 
async function executeWeatherTool(input: any) {
  // Simulate weather API call
  return {
    location: input.location,
    temperature: 72,
    condition: 'sunny',
  };
}

2. Message Batches

import Anthropic from '@anthropic-ai/sdk';
 
async function batchExample() {
  const client = new Anthropic();
  
  const batch = await client.messages.batches.create({
    requests: [
      {
        custom_id: 'analysis-1',
        params: {
          model: 'claude-sonnet-4-20250514',
          max_tokens: 1024,
          messages: [{ role: 'user', content: 'Analyze this code: console.log("Hello")' }],
        },
      },
      {
        custom_id: 'analysis-2',
        params: {
          model: 'claude-sonnet-4-20250514',
          max_tokens: 1024,
          messages: [{ role: 'user', content: 'Explain TypeScript interfaces' }],
        },
      },
    ],
  });
  
  // Check batch status
  const status = await client.messages.batches.retrieve(batch.id);
  console.log('Batch status:', status);
}

3. Code Review Tool Example

import { ClaudeCode } from '@anthropic-ai/claude-code';
import { readFileSync } from 'fs';
 
class CodeReviewTool {
  private claudeCode: ClaudeCode;
 
  constructor() {
    this.claudeCode = new ClaudeCode();
  }
 
  async reviewCode(filePath: string): Promise<any> {
    const code = readFileSync(filePath, 'utf-8');
    
    const review = await this.claudeCode.execute({
      prompt: `Review this TypeScript code for:
        - Potential bugs
        - Performance issues
        - Best practices
        - Security concerns
        
        Code:
        ${code}`,
      systemPrompt: "You are a senior TypeScript developer performing a thorough code review.",
      outputFormat: "json"
    });
 
    return review;
  }
 
  async suggestRefactoring(filePath: string): Promise<any> {
    const code = readFileSync(filePath, 'utf-8');
    
    return await this.claudeCode.execute({
      prompt: `Refactor this code to improve readability and performance: ${code}`,
      outputFormat: "json"
    });
  }
 
  async generateTests(filePath: string): Promise<any> {
    const code = readFileSync(filePath, 'utf-8');
    
    return await this.claudeCode.execute({
      prompt: `Generate comprehensive unit tests for this TypeScript code using Jest: ${code}`,
      outputFormat: "json"
    });
  }
}
 
// Usage
const reviewer = new CodeReviewTool();
reviewer.reviewCode('./src/utils/validator.ts')
  .then(review => console.log('Review:', review))
  .catch(error => console.error('Review failed:', error));

Practical Implementations

Code Review Assistant

A complete code review tool that analyzes TypeScript files:

import { query, type SDKMessage } from "@anthropic-ai/claude-code";
import { glob } from "glob";
import * as fs from "fs/promises";
 
interface CodeReviewResult {
  file: string;
  issues: Array<{
    line?: number;
    severity: 'error' | 'warning' | 'info';
    message: string;
    suggestion?: string;
  }>;
  score: number;
}
 
class CodeReviewAssistant {
  private abortController = new AbortController();
  
  async reviewProject(pattern: string = "src/**/*.ts"): Promise<CodeReviewResult[]> {
    const files = await glob(pattern);
    const results: CodeReviewResult[] = [];
    
    for (const file of files) {
      console.log(`Reviewing ${file}...`);
      const result = await this.reviewFile(file);
      results.push(result);
    }
    
    return results;
  }
  
  private async reviewFile(filePath: string): Promise<CodeReviewResult> {
    const code = await fs.readFile(filePath, 'utf-8');
    
    const prompt = `
Please review this TypeScript file for:
1. Code quality issues
2. Potential bugs
3. Performance problems
4. Security vulnerabilities
5. Best practice violations
 
File: ${filePath}
Code:
\`\`\`typescript
${code}
\`\`\`
 
Provide a structured review with specific line numbers where applicable.
Rate the overall code quality from 1-10.
`;
    
    const messages: SDKMessage[] = [];
    
    for await (const message of query({
      prompt,
      abortController: this.abortController,
      options: {
        maxTurns: 1,
        systemPrompt: "You are an expert TypeScript code reviewer. Be thorough but constructive."
      }
    })) {
      messages.push(message);
    }
    
    return this.parseReviewResult(filePath, messages);
  }
  
  private parseReviewResult(
    filePath: string, 
    messages: SDKMessage[]
  ): CodeReviewResult {
    // Extract assistant response
    const assistantMessage = messages.find(m => m.type === 'assistant');
    const content = assistantMessage?.data.message.content as string || '';
    
    // Parse the review (simplified - in practice, use structured output)
    const issues = this.extractIssues(content);
    const score = this.extractScore(content);
    
    return {
      file: filePath,
      issues,
      score
    };
  }
  
  private extractIssues(content: string): CodeReviewResult['issues'] {
    const issues: CodeReviewResult['issues'] = [];
    const lines = content.split('\n');
    
    for (const line of lines) {
      if (line.includes('Line') || line.includes('line')) {
        const lineMatch = line.match(/[Ll]ine (\d+)/);
        const lineNumber = lineMatch ? parseInt(lineMatch[1]) : undefined;
        
        let severity: 'error' | 'warning' | 'info' = 'info';
        if (line.toLowerCase().includes('error') || line.toLowerCase().includes('bug')) {
          severity = 'error';
        } else if (line.toLowerCase().includes('warning') || line.toLowerCase().includes('could')) {
          severity = 'warning';
        }
        
        issues.push({
          line: lineNumber,
          severity,
          message: line.trim()
        });
      }
    }
    
    return issues;
  }
  
  private extractScore(content: string): number {
    const scoreMatch = content.match(/(\d+)\/10/);
    return scoreMatch ? parseInt(scoreMatch[1]) : 5;
  }
  
  async generateReport(results: CodeReviewResult[]): Promise<string> {
    const totalScore = results.reduce((sum, r) => sum + r.score, 0) / results.length;
    const totalIssues = results.reduce((sum, r) => sum + r.issues.length, 0);
    
    let report = `# Code Review Report\n\n`;
    report += `**Overall Score**: ${totalScore.toFixed(1)}/10\n`;
    report += `**Total Issues**: ${totalIssues}\n\n`;
    
    for (const result of results) {
      report += `## ${result.file}\n`;
      report += `Score: ${result.score}/10\n\n`;
      
      if (result.issues.length > 0) {
        report += `### Issues:\n`;
        for (const issue of result.issues) {
          const icon = issue.severity === 'error' ? '❌' : 
                       issue.severity === 'warning' ? '⚠️' : 'ℹ️';
          report += `${icon} ${issue.line ? `Line ${issue.line}: ` : ''}${issue.message}\n`;
        }
      } else {
        report += `✅ No issues found\n`;
      }
      report += '\n';
    }
    
    return report;
  }
}
 
// Usage
async function main() {
  const reviewer = new CodeReviewAssistant();
  const results = await reviewer.reviewProject("src/**/*.ts");
  const report = await reviewer.generateReport(results);
  
  await fs.writeFile('code-review-report.md', report);
  console.log('Review complete! Report saved to code-review-report.md');
}

Interactive CLI Refactoring Tool

import { query } from "@anthropic-ai/claude-code";
import * as readline from 'readline/promises';
import * as fs from 'fs/promises';
import { diffLines } from 'diff';
import chalk from 'chalk';
 
class InteractiveRefactor {
  private rl: readline.Interface;
  private abortController = new AbortController();
  
  constructor() {
    this.rl = readline.createInterface({
      input: process.stdin,
      output: process.stdout
    });
  }
  
  async refactorFile(filePath: string) {
    const originalCode = await fs.readFile(filePath, 'utf-8');
    
    console.log(chalk.blue(`\nRefactoring: ${filePath}`));
    console.log(chalk.gray('Original code:'));
    console.log(this.formatCode(originalCode));
    
    const instruction = await this.rl.question(
      chalk.yellow('\nWhat would you like to refactor? ')
    );
    
    if (!instruction.trim()) {
      console.log('No changes requested.');
      return;
    }
    
    const refactoredCode = await this.performRefactoring(
      originalCode, 
      instruction,
      filePath
    );
    
    if (refactoredCode && refactoredCode !== originalCode) {
      await this.showDiff(originalCode, refactoredCode);
      
      const confirm = await this.rl.question(
        chalk.yellow('\nApply these changes? (y/n) ')
      );
      
      if (confirm.toLowerCase() === 'y') {
        await fs.writeFile(filePath, refactoredCode);
        console.log(chalk.green('✅ Changes applied successfully!'));
      } else {
        console.log(chalk.red('❌ Changes discarded.'));
      }
    }
  }
  
  private async performRefactoring(
    code: string, 
    instruction: string,
    filePath: string
  ): Promise<string | null> {
    const prompt = `
Refactor this TypeScript code according to the instruction.
Return ONLY the refactored code, no explanations.
 
File: ${filePath}
Current code:
\`\`\`typescript
${code}
\`\`\`
 
Instruction: ${instruction}
`;
    
    console.log(chalk.gray('\nRefactoring...'));
    
    let refactoredCode = '';
    
    for await (const message of query({
      prompt,
      abortController: this.abortController,
      options: {
        maxTurns: 1,
        systemPrompt: "You are a TypeScript refactoring expert. Return only code."
      }
    })) {
      if (message.type === 'assistant') {
        const content = message.data.message.content as string;
        // Extract code from markdown if present
        const codeMatch = content.match(/```(?:typescript|ts)?\n([\s\S]*?)\n```/);
        refactoredCode = codeMatch ? codeMatch[1] : content;
      }
    }
    
    return refactoredCode.trim();
  }
  
  private showDiff(original: string, refactored: string) {
    console.log(chalk.blue('\n--- Diff ---'));
    
    const diff = diffLines(original, refactored);
    
    diff.forEach(part => {
      const color = part.added ? chalk.green :
                   part.removed ? chalk.red :
                   chalk.gray;
      
      const prefix = part.added ? '+' :
                    part.removed ? '-' : ' ';
      
      const lines = part.value.split('\n').filter(line => line);
      lines.forEach(line => {
        console.log(color(`${prefix} ${line}`));
      });
    });
  }
  
  private formatCode(code: string): string {
    const lines = code.split('\n');
    return lines.map((line, i) => 
      chalk.gray(`${(i + 1).toString().padStart(3)} │ `) + line
    ).join('\n');
  }
  
  async close() {
    this.rl.close();
  }
}
 
// Usage
async function main() {
  const refactor = new InteractiveRefactor();
  
  try {
    // Process files from command line arguments
    const files = process.argv.slice(2);
    
    if (files.length === 0) {
      console.log('Usage: refactor <file1> [file2] ...');
      process.exit(1);
    }
    
    for (const file of files) {
      await refactor.refactorFile(file);
    }
  } finally {
    await refactor.close();
  }
}
 
main().catch(console.error);

Test Generation Pipeline

import { query } from "@anthropic-ai/claude-code";
import * as fs from 'fs/promises';
import * as path from 'path';
 
interface TestGenerationOptions {
  framework: 'jest' | 'mocha' | 'vitest';
  coverage: number;
  includeEdgeCases: boolean;
}
 
class TestGenerator {
  private abortController = new AbortController();
  
  async generateTests(
    sourcePath: string,
    options: TestGenerationOptions = {
      framework: 'jest',
      coverage: 80,
      includeEdgeCases: true
    }
  ): Promise<string> {
    const sourceCode = await fs.readFile(sourcePath, 'utf-8');
    const testPath = this.getTestPath(sourcePath);
    
    const prompt = `
Generate comprehensive unit tests for this TypeScript code.
 
Requirements:
- Use ${options.framework} as the testing framework
- Aim for ${options.coverage}% code coverage
- ${options.includeEdgeCases ? 'Include edge cases and error scenarios' : 'Focus on happy path'}
- Mock all external dependencies
- Use descriptive test names
- Group related tests in describe blocks
 
Source file: ${sourcePath}
Code:
\`\`\`typescript
${sourceCode}
\`\`\`
 
Generate the complete test file.
`;
    
    console.log(`Generating tests for ${sourcePath}...`);
    
    let testCode = '';
    
    for await (const message of query({
      prompt,
      abortController: this.abortController,
      options: {
        maxTurns: 1,
        systemPrompt: `You are an expert at writing ${options.framework} tests for TypeScript.`
      }
    })) {
      if (message.type === 'assistant') {
        const content = message.data.message.content as string;
        // Extract code from markdown
        const codeMatch = content.match(/```(?:typescript|ts)?\n([\s\S]*?)\n```/);
        testCode = codeMatch ? codeMatch[1] : content;
      }
    }
    
    // Save the test file
    await this.ensureTestDirectory(testPath);
    await fs.writeFile(testPath, testCode);
    
    console.log(`✅ Tests generated: ${testPath}`);
    
    return testPath;
  }
  
  private getTestPath(sourcePath: string): string {
    const parsed = path.parse(sourcePath);
    const testDir = parsed.dir.replace('/src', '/test');
    return path.join(testDir, `${parsed.name}.test${parsed.ext}`);
  }
  
  private async ensureTestDirectory(testPath: string) {
    const dir = path.dirname(testPath);
    await fs.mkdir(dir, { recursive: true });
  }
  
  async generateTestSuite(pattern: string): Promise<void> {
    const { glob } = await import('glob');
    const files = await glob(pattern);
    
    console.log(`Found ${files.length} files to test`);
    
    for (const file of files) {
      // Skip test files
      if (file.includes('.test.') || file.includes('.spec.')) {
        continue;
      }
      
      await this.generateTests(file);
    }
  }
  
  async analyzeTestCoverage(testPaths: string[]): Promise<void> {
    const prompt = `
Analyze these test files and provide a coverage report:
 
${testPaths.map(p => `File: ${p}`).join('\n')}
 
For each file, identify:
1. What is well tested
2. What might be missing coverage
3. Suggestions for additional tests
`;
    
    console.log('\n📊 Analyzing test coverage...');
    
    for await (const message of query({
      prompt,
      abortController: this.abortController,
      options: { maxTurns: 1 }
    })) {
      if (message.type === 'assistant') {
        console.log(message.data.message.content);
      }
    }
  }
}
 
// Usage with CLI
async function main() {
  const generator = new TestGenerator();
  
  const command = process.argv[2];
  const target = process.argv[3];
  
  switch (command) {
    case 'generate':
      if (!target) {
        console.error('Usage: test-gen generate <file-or-pattern>');
        process.exit(1);
      }
      
      if (target.includes('*')) {
        await generator.generateTestSuite(target);
      } else {
        await generator.generateTests(target);
      }
      break;
      
    case 'analyze':
      const testFiles = process.argv.slice(3);
      await generator.analyzeTestCoverage(testFiles);
      break;
      
    default:
      console.log('Commands:');
      console.log('  generate <file>    Generate tests for a file');
      console.log('  generate <pattern> Generate tests for matching files');
      console.log('  analyze <files...> Analyze test coverage');
  }
}
 
main().catch(console.error);

Documentation Generator

import { query } from "@anthropic-ai/claude-code";
import * as fs from 'fs/promises';
import * as path from 'path';
 
interface DocGenerationOptions {
  format: 'markdown' | 'jsdoc' | 'typedoc';
  includeExamples: boolean;
  includeApi: boolean;
}
 
class DocumentationGenerator {
  private abortController = new AbortController();
  
  async generateDocs(
    sourcePath: string,
    options: DocGenerationOptions = {
      format: 'markdown',
      includeExamples: true,
      includeApi: true
    }
  ): Promise<string> {
    const sourceCode = await fs.readFile(sourcePath, 'utf-8');
    
    const prompt = `
Generate comprehensive documentation for this TypeScript code.
 
Requirements:
- Format: ${options.format}
- ${options.includeExamples ? 'Include usage examples' : 'Skip examples'}
- ${options.includeApi ? 'Include detailed API documentation' : 'Overview only'}
- Document all public APIs
- Explain complex logic
- Note any important edge cases or limitations
 
File: ${sourcePath}
Code:
\`\`\`typescript
${sourceCode}
\`\`\`
`;
    
    let documentation = '';
    
    for await (const message of query({
      prompt,
      abortController: this.abortController,
      options: {
        maxTurns: 1,
        systemPrompt: "You are a technical documentation expert."
      }
    })) {
      if (message.type === 'assistant') {
        documentation = message.data.message.content as string;
      }
    }
    
    return documentation;
  }
  
  async generateProjectDocs(projectPath: string): Promise<void> {
    const readmePath = path.join(projectPath, 'README.md');
    const packageJsonPath = path.join(projectPath, 'package.json');
    
    const packageJson = JSON.parse(
      await fs.readFile(packageJsonPath, 'utf-8')
    );
    
    const prompt = `
Generate a comprehensive README.md for this TypeScript project:
 
Project: ${packageJson.name}
Description: ${packageJson.description || 'No description'}
Version: ${packageJson.version}
 
Include:
1. Project overview
2. Installation instructions
3. Quick start guide
4. API documentation
5. Configuration options
6. Examples
7. Contributing guidelines
8. License information
 
Make it professional and developer-friendly.
`;
    
    console.log('Generating project documentation...');
    
    let readme = '';
    
    for await (const message of query({
      prompt,
      abortController: this.abortController,
      options: { maxTurns: 1 }
    })) {
      if (message.type === 'assistant') {
        readme = message.data.message.content as string;
      }
    }
    
    await fs.writeFile(readmePath, readme);
    console.log(`✅ README.md generated at ${readmePath}`);
  }
  
  async generateApiReference(
    sourceFiles: string[],
    outputPath: string
  ): Promise<void> {
    const apiDoc = ['# API Reference\n'];
    
    for (const file of sourceFiles) {
      const doc = await this.generateDocs(file, {
        format: 'markdown',
        includeExamples: true,
        includeApi: true
      });
      
      apiDoc.push(`## ${path.basename(file)}\n`);
      apiDoc.push(doc);
      apiDoc.push('\n---\n');
    }
    
    await fs.writeFile(outputPath, apiDoc.join('\n'));
    console.log(`✅ API reference generated at ${outputPath}`);
  }
}

Code Migration Assistant

import { query } from "@anthropic-ai/claude-code";
import * as fs from 'fs/promises';
import * as path from 'path';
 
interface MigrationOptions {
  from: string;
  to: string;
  preserveLogic: boolean;
  modernize: boolean;
}
 
class CodeMigrationAssistant {
  private abortController = new AbortController();
  
  async migrateFile(
    filePath: string,
    options: MigrationOptions
  ): Promise<string> {
    const sourceCode = await fs.readFile(filePath, 'utf-8');
    
    const prompt = `
Migrate this code from ${options.from} to ${options.to}.
 
Requirements:
- ${options.preserveLogic ? 'Preserve exact logic and behavior' : 'Optimize for the target platform'}
- ${options.modernize ? 'Use modern language features and best practices' : 'Keep similar structure'}
- Handle all imports and dependencies
- Maintain the same API surface
- Add appropriate type annotations (if applicable)
 
Source (${options.from}):
\`\`\`
${sourceCode}
\`\`\`
 
Provide the complete migrated code.
`;
    
    console.log(`Migrating ${filePath} from ${options.from} to ${options.to}...`);
    
    let migratedCode = '';
    
    for await (const message of query({
      prompt,
      abortController: this.abortController,
      options: {
        maxTurns: 1,
        systemPrompt: `You are an expert at migrating code between languages and frameworks.`
      }
    })) {
      if (message.type === 'assistant') {
        const content = message.data.message.content as string;
        const codeMatch = content.match(/```[\s\S]*?\n([\s\S]*?)\n```/);
        migratedCode = codeMatch ? codeMatch[1] : content;
      }
    }
    
    return migratedCode;
  }
  
  async migrateProject(
    sourceDir: string,
    targetDir: string,
    options: MigrationOptions
  ): Promise<void> {
    const { glob } = await import('glob');
    const files = await glob(`${sourceDir}/**/*.{js,ts,jsx,tsx}`);
    
    console.log(`Found ${files.length} files to migrate`);
    
    for (const file of files) {
      const relativePath = path.relative(sourceDir, file);
      const targetPath = path.join(targetDir, relativePath);
      
      // Update file extension based on migration
      const newPath = this.updateFileExtension(targetPath, options);
      
      // Ensure directory exists
      await fs.mkdir(path.dirname(newPath), { recursive: true });
      
      // Migrate the file
      const migratedCode = await this.migrateFile(file, options);
      await fs.writeFile(newPath, migratedCode);
      
      console.log(`✅ ${relativePath} → ${path.relative(targetDir, newPath)}`);
    }
    
    // Generate migration report
    await this.generateMigrationReport(sourceDir, targetDir, options);
  }
  
  private updateFileExtension(
    filePath: string,
    options: MigrationOptions
  ): string {
    const extensionMap: Record<string, Record<string, string>> = {
      'JavaScript': { ts: 'js', tsx: 'jsx' },
      'TypeScript': { js: 'ts', jsx: 'tsx' },
      'React': { js: 'jsx', ts: 'tsx' },
      'Vue': { js: 'vue', ts: 'vue' },
    };
    
    const parsed = path.parse(filePath);
    const currentExt = parsed.ext.slice(1);
    const newExt = extensionMap[options.to]?.[currentExt] || currentExt;
    
    return path.join(parsed.dir, `${parsed.name}.${newExt}`);
  }
  
  private async generateMigrationReport(
    sourceDir: string,
    targetDir: string,
    options: MigrationOptions
  ): Promise<void> {
    const report = `# Migration Report
 
## Summary
- **From**: ${options.from}
- **To**: ${options.to}
- **Source**: ${sourceDir}
- **Target**: ${targetDir}
- **Date**: ${new Date().toISOString()}
 
## Migration Options
- Preserve Logic: ${options.preserveLogic}
- Modernize: ${options.modernize}
 
## Next Steps
1. Review the migrated code
2. Update dependencies in package.json
3. Run tests to ensure functionality
4. Update build configuration
5. Update documentation
`;
    
    await fs.writeFile(
      path.join(targetDir, 'MIGRATION_REPORT.md'),
      report
    );
  }
}

Real-time Code Assistant

import { query } from "@anthropic-ai/claude-code";
import * as chokidar from 'chokidar';
import * as fs from 'fs/promises';
 
class RealtimeCodeAssistant {
  private watcher: chokidar.FSWatcher;
  private abortController = new AbortController();
  
  constructor(private watchPath: string) {
    this.watcher = chokidar.watch(watchPath, {
      ignored: /(^|[\/\\])\../, // ignore dotfiles
      persistent: true
    });
  }
  
  start() {
    console.log(`👀 Watching for changes in ${this.watchPath}`);
    
    this.watcher
      .on('change', async (path) => {
        console.log(`\n📝 File changed: ${path}`);
        await this.analyzeChange(path);
      })
      .on('add', async (path) => {
        console.log(`\n➕ File added: ${path}`);
        await this.suggestBoilerplate(path);
      });
  }
  
  private async analyzeChange(filePath: string) {
    const content = await fs.readFile(filePath, 'utf-8');
    
    // Look for TODO comments or specific patterns
    const todos = content.match(/\/\/\s*TODO:.*$/gm) || [];
    const fixmes = content.match(/\/\/\s*FIXME:.*$/gm) || [];
    
    if (todos.length > 0 || fixmes.length > 0) {
      console.log('\n🎯 Found action items:');
      [...todos, ...fixmes].forEach(item => console.log(`  ${item}`));
      
      const prompt = `
Help with these TODOs and FIXMEs in ${filePath}:
 
${[...todos, ...fixmes].join('\n')}
 
Provide implementation suggestions for each.
`;
      
      for await (const message of query({
        prompt,
        abortController: this.abortController,
        options: { maxTurns: 1 }
      })) {
        if (message.type === 'assistant') {
          console.log('\n💡 Suggestions:');
          console.log(message.data.message.content);
        }
      }
    }
  }
  
  private async suggestBoilerplate(filePath: string) {
    if (!filePath.endsWith('.ts') && !filePath.endsWith('.tsx')) {
      return;
    }
    
    const prompt = `
Suggest appropriate boilerplate code for a new file: ${filePath}
 
Consider:
- File name and location
- Common patterns for this type of file
- TypeScript best practices
`;
    
    for await (const message of query({
      prompt,
      abortController: this.abortController,
      options: { maxTurns: 1 }
    })) {
      if (message.type === 'assistant') {
        console.log('\n💡 Suggested boilerplate:');
        console.log(message.data.message.content);
      }
    }
  }
  
  stop() {
    this.watcher.close();
    this.abortController.abort();
  }
}
 
// Usage
const assistant = new RealtimeCodeAssistant('./src');
assistant.start();
 
// Graceful shutdown
process.on('SIGINT', () => {
  console.log('\n👋 Stopping assistant...');
  assistant.stop();
  process.exit(0);
});

Integration Patterns

Stream Processing with Progress

import { query, type SDKMessage } from "@anthropic-ai/claude-code";
 
async function streamWithProgress(prompt: string) {
  const messages: SDKMessage[] = [];
  let totalTokens = 0;
  
  console.log('🤖 Claude is thinking...\n');
  
  for await (const message of query({
    prompt,
    abortController: new AbortController()
  })) {
    messages.push(message);
    
    if (message.type === 'assistant') {
      // Stream content as it arrives
      process.stdout.write(message.data.message.content);
    } else if (message.type === 'result') {
      console.log('\n\n📊 Summary:');
      console.log(`- Total time: ${message.data.total_time_ms}ms`);
      console.log(`- API time: ${message.data.duration_api_ms}ms`);
      console.log(`- Cost: $${message.data.total_cost_usd}`);
      console.log(`- Turns: ${message.data.num_turns}`);
    }
  }
  
  return messages;
}

Cancellable Stream with Timeout

import { query } from "@anthropic-ai/claude-code";
 
class StreamManager {
  private controller = new AbortController();
  
  async streamWithTimeout(prompt: string, timeoutMs: number = 30000) {
    const timeout = setTimeout(() => {
      console.log('\n⏱️ Timeout reached, cancelling...');
      this.controller.abort();
    }, timeoutMs);
    
    try {
      for await (const message of query({
        prompt,
        abortController: this.controller
      })) {
        if (message.type === 'assistant') {
          process.stdout.write(message.data.message.content);
        }
      }
    } catch (error) {
      if (error.name === 'AbortError') {
        console.log('\n❌ Stream cancelled');
      } else {
        throw error;
      }
    } finally {
      clearTimeout(timeout);
    }
  }
  
  cancel() {
    this.controller.abort();
  }
}

Comprehensive Error Handler

import { query } from "@anthropic-ai/claude-code";
 
class ErrorHandler {
  async safeQuery(prompt: string, retries: number = 3) {
    for (let attempt = 1; attempt <= retries; attempt++) {
      try {
        const messages = [];
        
        for await (const message of query({ prompt })) {
          messages.push(message);
          
          if (message.type === 'result' && message.data.result === 'error') {
            throw new Error(`Query failed: ${message.data.error_message}`);
          }
        }
        
        return messages;
      } catch (error) {
        console.error(`Attempt ${attempt} failed:`, error.message);
        
        if (attempt === retries) {
          throw error;
        }
        
        // Exponential backoff
        const delay = Math.pow(2, attempt) * 1000;
        console.log(`Retrying in ${delay}ms...`);
        await new Promise(resolve => setTimeout(resolve, delay));
      }
    }
  }
}

Express.js API Integration

import express from 'express';
import { query } from "@anthropic-ai/claude-code";
 
const app = express();
app.use(express.json());
 
app.post('/api/claude', async (req, res) => {
  const { prompt, maxTurns = 3 } = req.body;
  
  if (!prompt) {
    return res.status(400).json({ error: 'Prompt is required' });
  }
  
  const controller = new AbortController();
  
  // Set timeout
  const timeout = setTimeout(() => controller.abort(), 60000);
  
  try {
    const messages = [];
    
    for await (const message of query({
      prompt,
      abortController: controller,
      options: { maxTurns }
    })) {
      messages.push(message);
    }
    
    clearTimeout(timeout);
    
    // Extract response
    const response = messages
      .filter(m => m.type === 'assistant')
      .map(m => m.data.message.content)
      .join('\n');
    
    const result = messages.find(m => m.type === 'result');
    
    res.json({
      response,
      cost: result?.data.total_cost_usd,
      duration: result?.data.total_time_ms
    });
  } catch (error) {
    if (error.name === 'AbortError') {
      res.status(408).json({ error: 'Request timeout' });
    } else {
      res.status(500).json({ error: 'Internal server error' });
    }
  }
});
 
app.listen(3000, () => {
  console.log('Server running on http://localhost:3000');
});

WebSocket Real-time Streaming

import { WebSocketServer } from 'ws';
import { query } from "@anthropic-ai/claude-code";
 
const wss = new WebSocketServer({ port: 8080 });
 
wss.on('connection', (ws) => {
  console.log('Client connected');
  
  ws.on('message', async (data) => {
    const { prompt } = JSON.parse(data.toString());
    const controller = new AbortController();
    
    // Allow client to cancel
    ws.on('close', () => controller.abort());
    
    try {
      for await (const message of query({
        prompt,
        abortController: controller
      })) {
        ws.send(JSON.stringify(message));
      }
    } catch (error) {
      if (error.name !== 'AbortError') {
        ws.send(JSON.stringify({ 
          type: 'error', 
          error: error.message 
        }));
      }
    }
  });
});

Workshop Exercise Ideas

Exercise 1: Build a CLI Tool

Create a command-line tool that uses Claude to:

  • Generate boilerplate code
  • Explain code snippets
  • Convert code between languages
  • Generate documentation

Exercise 2: Real-time Code Assistant

Build a VS Code extension or web app that:

  • Provides code suggestions as you type
  • Explains selected code
  • Suggests improvements
  • Generates tests for functions

Exercise 3: Documentation Generator

Create a tool that:

  • Analyzes TypeScript files
  • Generates comprehensive documentation
  • Creates usage examples
  • Generates README files

Exercise 4: Code Migration Assistant

Build a tool that helps migrate code:

  • From JavaScript to TypeScript
  • Between different frameworks
  • Update deprecated APIs
  • Modernize legacy code

Exercise 5: Interactive Tutorial System

Create an educational platform that:

  • Generates coding exercises
  • Provides hints and explanations
  • Reviews submitted solutions
  • Tracks learning progress

Real-World Projects

1. Claude Artifact Runner

Template for converting Claude AI artifacts into React applications:

2. Claude Flow

AI-powered development orchestration with enterprise-grade architecture:

  • GitHub: ruvnet/claude-flow
  • Features: GitHub integration, swarm intelligence, 84.8% SWE-Bench solve rate

3. Claude Task Master

AI-powered task management for development:

4. Claude Code MCP

Model Context Protocol implementation:

5. Claude GitHub Action

Automated PR and issue assistance:

Best Practices

  1. Environment Variables: Always use environment variables for API keys
  2. Error Handling: Implement comprehensive error handling for API calls
  3. Rate Limiting: Implement exponential backoff for rate limit errors
  4. Streaming: Use streaming for better user experience with long responses
  5. Type Safety: Leverage TypeScript types provided by the SDK
  6. Security: Never expose API keys in client-side code
  7. Testing: Write tests for your Claude integrations
  8. Monitoring: Log API usage and errors for debugging
  9. Memory Management: Clean up resources (abort controllers, watchers) when done
  10. User Experience: Provide visual feedback during long-running operations

Additional Resources