How ChatGPT and TypeScript Become Best Friends
Imagine: you're writing code in TypeScript, and suddenly your service gains a superpower — the ability to understand and generate human text. The ChatGPT API makes this a reality. In this article, we won't just connect the API — we'll build a full-fledged module for communicating with the neural network that is robust, typed, and production-ready.
If you think AI integration is something out of science fiction or the domain of giants like Google, I'm happy to reassure you: OpenAI provides a simple REST API, and TypeScript with its strict typing makes working with it safe and predictable. Let's figure it out in practice.
Environment Setup: What You Need to Install
Before writing code, let's make sure you have everything you need. To work with the ChatGPT API in TypeScript, you'll need:
- Node.js version 18 or higher (I recommend 20 LTS)
- npm or yarn for package management
- OpenAI API key — get it at platform.openai.com
- Code editor (VS Code, WebStorm — any convenient one)
Let's create a new project and install the dependencies:
mkdir chatgpt-typescriptcd chatgpt-typescriptnpm init -ynpm install openai dotenvnpm install -D typescript @types/node ts-nodeNote: we are using the official SDK from OpenAI, which works great with TypeScript. The dotenv package will be needed for secure storage of the API key.
Configuring TypeScript and Environment Variables
Let's create a tsconfig.json file with basic settings:
{ "compilerOptions": { "target": "ES2020", "module": "commonjs", "lib": ["ES2020"], "outDir": "./dist", "rootDir": "./src", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true }, "include": ["src/**/*"]}Now let's create a .env file in the project root:
OPENAI_API_KEY=your_super_secret_keyImportant: add .env to .gitignore to avoid accidentally committing the key to the repository!
Writing the First Request to ChatGPT in TypeScript
Let's create a src folder and an index.ts file. Let's start simple: send a message and get a response.
import OpenAI from 'openai';import dotenv from 'dotenv';
dotenv.config();
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY,});
async function chatWithGPT(prompt: string): Promise<string> { try { const response = await openai.chat.completions.create({ model: 'gpt-4', messages: [ { role: 'system', content: 'You are a helpful assistant.' }, { role: 'user', content: prompt }, ], temperature: 0.7, max_tokens: 500, });
return response.choices[0]?.message?.content || 'No response'; } catch (error) { console.error('Error when requesting ChatGPT:', error); throw error; }}
// Usage(async () => { const answer = await chatWithGPT('Tell a short joke about programmers'); console.log('ChatGPT says:', answer);})();Run the code with the command npx ts-node src/index.ts. If everything is configured correctly, you will see a response from the neural network. Notice the typing: TypeScript automatically hints at the structure of the response object, making development comfortable.
Breakdown of Key Parameters
- model:
gpt-4— the smartest model available today. To save costs, you can usegpt-3.5-turbo. - messages: an array of messages forming the conversation context. The
systemmessage sets the assistant's behavior,usermessages are your queries. - temperature: controls the randomness of the response (0 — deterministic, 1 — creative chaos).
- max_tokens: the maximum length of the response in tokens (roughly, one token ≈ 0.75 words).
Error Handling: Making the Code Resilient
In production, you can't just let errors crash the application. Let's add proper error handling:
import OpenAI from 'openai';import dotenv from 'dotenv';
dotenv.config();
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY, timeout: 30000, // 30 second timeout maxRetries: 3, // automatic retries on failure});
enum ChatGPTErrorType { RATE_LIMIT = 'rate_limit', AUTH_ERROR = 'auth_error', NETWORK_ERROR = 'network_error', UNKNOWN = 'unknown',}
interface ChatGPTResponse { success: boolean; data?: string; error?: { type: ChatGPTErrorType; message: string; };}
function classifyError(error: any): ChatGPTErrorType { if (error.status === 429) return ChatGPTErrorType.RATE_LIMIT; if (error.status === 401) return ChatGPTErrorType.AUTH_ERROR; if (error.code === 'ECONNREFUSED' || error.code === 'ETIMEDOUT') { return ChatGPTErrorType.NETWORK_ERROR; } return ChatGPTErrorType.UNKNOWN;}
async function safeChatWithGPT(prompt: string): Promise<ChatGPTResponse> { try { const response = await openai.chat.completions.create({ model: 'gpt-4', messages: [ { role: 'system', content: 'You are a helpful assistant.' }, { role: 'user', content: prompt }, ], temperature: 0.7, max_tokens: 500, });
return { success: true, data: response.choices[0]?.message?.content || 'No response', }; } catch (error) { const errorType = classifyError(error); const errorMessage = error instanceof Error ? error.message : 'Unknown error';
console.error(`[${errorType}] ChatGPT API error:`, errorMessage);
return { success: false, error: { type: errorType, message: errorMessage, }, }; }}Now our function returns a structured response instead of throwing exceptions. This makes it much easier to handle errors in the calling code.
Creating a Full-Fledged ChatGPT Module
Let's organize the code into a separate module for reuse:
// src/chatgpt.tsimport OpenAI from 'openai';import dotenv from 'dotenv';
dotenv.config();
interface ChatConfig { model?: string; temperature?: number; maxTokens?: number; systemPrompt?: string;}
interface ChatMessage { role: 'user' | 'assistant' | 'system'; content: string;}
class ChatGPTClient { private client: OpenAI; private defaultConfig: Required<ChatConfig>;
constructor(config?: ChatConfig) { this.client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY, timeout: 30000, maxRetries: 3, });
this.defaultConfig = { model: config?.model || 'gpt-4', temperature: config?.temperature ?? 0.7, maxTokens: config?.maxTokens ?? 500, systemPrompt: config?.systemPrompt || 'You are a helpful assistant.', }; }
async sendMessage( userMessage: string, conversationHistory: ChatMessage[] = [] ): Promise<string> { const messages: ChatMessage[] = [ { role: 'system', content: this.defaultConfig.systemPrompt }, ...conversationHistory, { role: 'user', content: userMessage }, ];
try { const response = await this.client.chat.completions.create({ model: this.defaultConfig.model, messages, temperature: this.defaultConfig.temperature, max_tokens: this.defaultConfig.maxTokens, });
return response.choices[0]?.message?.content || ''; } catch (error) { console.error('ChatGPT Client Error:', error); throw error; } }
async *streamMessage(userMessage: string): AsyncGenerator<string> { const messages: ChatMessage[] = [ { role: 'system', content: this.defaultConfig.systemPrompt }, { role: 'user', content: userMessage }, ];
const stream = await this.client.chat.completions.create({ model: this.defaultConfig.model, messages, temperature: this.defaultConfig.temperature, max_tokens: this.defaultConfig.maxTokens, stream: true, });
for await (const chunk of stream) { const content = chunk.choices[0]?.delta?.content || ''; if (content) { yield content; } } }}
export { ChatGPTClient, ChatConfig, ChatMessage };Now using the module is as easy as:
// src/index.tsimport { ChatGPTClient } from './chatgpt';
async function main() { const assistant = new ChatGPTClient({ model: 'gpt-4', temperature: 0.8, systemPrompt: 'You are a witty assistant who loves programming jokes.', });
const response = await assistant.sendMessage('Why do programmers prefer dark mode?'); console.log('Response:', response);
// Example with streaming console.log('Streaming response:'); for await (const chunk of assistant.streamMessage('Tell me a story about a robot')) { process.stdout.write(chunk); }}
main().catch(console.error);Practical Tips for Working with ChatGPT API
Here are a few recommendations that will help you avoid common pitfalls:
- Monitor token consumption: each request costs money. Use the
response.usagefield to track expenses. - Cache repeated requests: if users often ask the same questions, store responses in Redis or a database.
- Use streaming: for long responses, enable
stream: true— this reduces the user's waiting time. - Limit the conversation context: the longer the message history, the more expensive the request. Trim old messages.
- Add logging: record all requests and responses for debugging and analytics.
Conclusion: What's Next?
We've built a solid foundation for integrating ChatGPT into a TypeScript project. Now you can:
- Create a chatbot for your website
- Automate content generation
- Build an intelligent assistant for data analysis
- Integrate AI into existing business processes
TypeScript makes working with the OpenAI API safe and predictable, and our module is ready for expansion. Add support for functions (function calling), implement your own prompt caching, or create a full-fledged SDK for your product.
The code from this article is available on GitHub. Experiment, break things, and build amazing AI-powered products!