TypeScript AI API Basics
A practical guide to connecting TypeScript applications to modern artificial intelligence models using type-safe API client patterns.
TL;DR
- Store secret keys in
process.envto prevent credential exposure. - Define a unified
LLMMessageinterface for universal provider compatibility. - Use
AbortSignalparameters to cancel long-running model network requests.
Client Initialization
OpenAI client setupInitialize official OpenAI client with environment keys.
import OpenAI from 'openai';
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
});Anthropic client setupCreate Anthropic instance targeting Claude foundation models.
import Anthropic from '@anthropic-ai/sdk';
const anthropic = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY,
});Google GenAI setupInstantiate Google GenAI client targeting Gemini endpoints.
import { GoogleGenAI } from '@google/genai';
const ai = new GoogleGenAI({
apiKey: process.env.GEMINI_API_KEY,
});Universal Message Modeling
type MessageRoleDefine supported participant roles within prompt conversations.
type MessageRole =
| 'system'
| 'user'
| 'assistant'
| 'tool';interface ChatMessageRepresent standardized dialogue item across providers.
interface ChatMessage {
role: MessageRole;
content: string;
name?: string;
}interface RequestConfigGroup core hyperparameter options for prompt execution.
interface RequestConfig {
model: string;
temperature?: number;
maxTokens?: number;
signal?: AbortSignal;
}Executing Completions
openai.chat.completionsExecute chat completion against OpenAI chat models.
const res = await openai.chat.completions.create({
model: 'gpt-4o',
messages: [{ role: 'user', content: 'Hello!' }],
temperature: 0.7,
});
const reply = res.choices[0].message.content;anthropic.messagesSend message requests to Anthropic Claude models.
const msg = await anthropic.messages.create({
model: 'claude-3-5-sonnet-20241022',
max_tokens: 1024,
messages: [{ role: 'user', content: 'Hello!' }],
});
const text = msg.content[0].text;ai.models.generateContentInvoke Gemini models using Google standard SDK.
const geminiRes = await ai.models.generateContent({
model: 'gemini-2.0-flash',
contents: 'Summarize TypeScript in 10 words.',
});
const summary = geminiRes.text;Request Lifecycle Control
AbortController signalEnforce strict network timeouts on slow completions.
const c = new AbortController();
const t = setTimeout(() => c.abort(), 5000);
try {
await openai.chat.completions.create(
{ model: 'gpt-4o', messages: [] },
{ signal: c.signal }
);
} finally {
clearTimeout(t);
}Token usage auditingCapture prompt and completion token counts from response.
type Usage = { prompt: number; total: number };
const usage: Usage = {
prompt: res.usage?.prompt_tokens ?? 0,
total: res.usage?.total_tokens ?? 0,
};Provider adapter patternExpose universal interface to decouple model dependencies.
interface AIProvider {
complete(
prompt: string, opts?: Opts
): Promise<string>;
}Tips
- Wrap provider SDK clients in custom TypeScript adapter classes implementing
AIProviderto swap underlying models without breaking calling application code. - Specify explicit
max_tokenslimits on all model requests to avoid unexpected generation costs and latency spikes.
Warnings
- Never expose secret API keys like
process.env.OPENAI_API_KEYinside client-side browser code or public single-page application script tags. - Avoid hardcoding raw model string names like
'gpt-4o'directly into business logic without strict TypeScript union types.
In Practice
A provider-agnostic TypeScript client wrapper that completes prompts with configurable fallback models.
- Define an AIProvider interface to standardize model invocation signatures.
- Implement an OpenAI adapter that maps standard inputs to chat completions.
- Include an AbortSignal check to cleanly abort long-running requests.
- Extract text content safely while tracking prompt and output tokens.
interface AIProvider {
complete(prompt: string): Promise<string>;
}
class OpenAIProvider implements AIProvider {
constructor(private client: OpenAI) {}
async complete(prompt: string): Promise<string> {
const res = await this.client.chat.completions.create({
model: 'gpt-4o-mini',
messages: [{ role: 'user', content: prompt }],
max_tokens: 300,
});
return res.choices[0]?.message?.content ?? '';
}
}FAQ
Define a union of roles including system, user, and assistant with string content. When mapping to Anthropic messages.create, extract the system string into the top-level parameter while sending remaining items in the message array.
Load keys exclusively on the server using process.env.AI_API_KEY or secret managers. If you use Next.js, ensure you never prefix sensitive keys with NEXT_PUBLIC_ so they remain stripped from browser bundles.
Pass an AbortSignal from an AbortController into the request options. Calling abort() immediately cancels the HTTP connection and prevents unnecessary token billing.