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
- Installation & Setup
- Basic Usage Examples
- Streaming Examples
- React & Next.js Integration
- Advanced Features
- Practical Implementations
- Integration Patterns
- Workshop Exercise Ideas
- Real-World Projects
- Best Practices
- Additional Resources
Installation & Setup
Installing Claude Code CLI
# Global installation
npm install -g @anthropic-ai/claude-code
# Project installation
npm install @anthropic-ai/claude-codeInstalling Anthropic SDK
npm install @anthropic-ai/sdkEnvironment 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:
- GitHub: claudio-silva/claude-artifact-runner
- Features: TypeScript, React 18, Vite, Tailwind CSS, Shadcn UI
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:
- GitHub: eyaltoledano/claude-task-master
- Features: Works with Cursor, Lovable, Windsurf, and other AI tools
4. Claude Code MCP
Model Context Protocol implementation:
- GitHub: auchenberg/claude-code-mcp
- Features: MCP server interface for Claude Code
5. Claude GitHub Action
Automated PR and issue assistance:
- GitHub: anthropics/claude-code-action
- Features: Trigger-based activation, multiple auth methods
Best Practices
- Environment Variables: Always use environment variables for API keys
- Error Handling: Implement comprehensive error handling for API calls
- Rate Limiting: Implement exponential backoff for rate limit errors
- Streaming: Use streaming for better user experience with long responses
- Type Safety: Leverage TypeScript types provided by the SDK
- Security: Never expose API keys in client-side code
- Testing: Write tests for your Claude integrations
- Monitoring: Log API usage and errors for debugging
- Memory Management: Clean up resources (abort controllers, watchers) when done
- User Experience: Provide visual feedback during long-running operations
Additional Resources
- Official Anthropic SDK
- Claude Code Documentation
- Anthropic Academy
- Model Context Protocol
- Community Examples
Related Topics
- TypeScript SDK Documentation - Complete SDK documentation
- Getting Started
- Streaming Patterns - Advanced streaming techniques
- Error Handling Guide
- Tool Integration Examples
- Troubleshooting Common Issues
- Subagents TypeScript Integration
- Workshop Exercises - More hands-on exercises
- Claude Code Hooks Examples
- Best Practices - Production-ready patterns
- Advanced Patterns - Complex scenarios