Type-safe Claude API calls in TypeScript. Use @anthropic-ai/sdk with full type inference for messages, tool use, streaming, and response handling.
The @anthropic-ai/sdk package ships its own TypeScript declarations. No extra @types package needed.
import Anthropic from "@anthropic-ai/sdk";
import type { Message, TextBlock } from "@anthropic-ai/sdk/resources/messages";
const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
async function ask(prompt: string): Promise<string> {
const message: Message = await client.messages.create({
model: "claude-sonnet-4-6",
max_tokens: 1024,
messages: [{ role: "user", content: prompt }]
});
const textBlock = message.content.find((b): b is TextBlock => b.type === "text");
return textBlock?.text ?? "";
}
const result = await ask("What are the SOLID principles?");
console.log(result);
import type { MessageParam, SystemPrompt } from "@anthropic-ai/sdk/resources/messages";
const systemPrompt: SystemPrompt = "You are a TypeScript expert. Respond with working, type-safe code.";
const messages: MessageParam[] = [
{ role: "user", content: "How do I type a generic fetch wrapper?" }
];
const response = await client.messages.create({
model: "claude-sonnet-4-6",
max_tokens: 2048,
system: systemPrompt,
messages
});
// app/api/chat/route.ts
import { NextRequest } from "next/server";
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
export async function POST(req: NextRequest) {
const { prompt } = await req.json() as { prompt: string };
const stream = await client.messages.stream({
model: "claude-sonnet-4-6",
max_tokens: 1024,
messages: [{ role: "user", content: prompt }]
});
const encoder = new TextEncoder();
const readable = new ReadableStream({
async start(controller) {
for await (const chunk of stream) {
if (chunk.type === "content_block_delta" && chunk.delta.type === "text_delta") {
controller.enqueue(encoder.encode(chunk.delta.text));
}
}
controller.close();
}
});
return new Response(readable, {
headers: { "Content-Type": "text/plain; charset=utf-8" }
});
}
import type { Tool, ToolUseBlock } from "@anthropic-ai/sdk/resources/messages";
const calculatorTool: Tool = {
name: "calculate",
description: "Evaluate a mathematical expression.",
input_schema: {
type: "object" as const,
properties: { expression: { type: "string" } },
required: ["expression"]
}
};
type CalculateInput = { expression: string };
const response = await client.messages.create({
model: "claude-sonnet-4-6",
max_tokens: 512,
tools: [calculatorTool],
messages: [{ role: "user", content: "What is 17 * 24 + 387?" }]
});
for (const block of response.content) {
if (block.type === "tool_use") {
const input = (block as ToolUseBlock).input as CalculateInput;
console.log("Expression to evaluate:", input.expression);
}
}
See the streaming Node.js example for more streaming patterns, or the Node.js tool use guide for full agent loops.