20 Prompts for Generating JavaScript and TypeScript Code
Introduction
JavaScript and TypeScript are the backbone of modern web development. From building interactive React UIs to scaling Node.js backends, the ability to quickly generate high-quality code is a superpower. As of 2026, AI-assisted coding tools have matured significantly, offering developers a chance to reduce boilerplate, catch edge cases early, and prototype faster. However, the quality of the output depends heavily on the clarity and specificity of the prompts you provide.
This article is a practical cheat sheet of 20 ready-to-use prompts for generating JavaScript and TypeScript code. Each prompt is designed to be copy-paste ready, with a clear explanation of its use case and a concrete example. Whether you are a beginner looking for utility functions or a senior engineer architecting a React component, you will find prompts that save time and improve code quality.
Why Use Prompts for Code Generation?
Using well-crafted prompts is not just about speed — it is about reducing cognitive load. A good prompt acts as a specification, forcing you to think through requirements before writing a single line. In a 2025 Stack Overflow survey of over 90,000 developers, nearly 70% reported using AI tools in their workflow, with the most common use being code generation and debugging. The key takeaway: the developers who get the most value are those who write precise, context-rich prompts.
Prompt 1: Generate a React Functional Component with TypeScript
Task: Create a reusable React component with TypeScript props and state.
Prompt:
Generate a React functional component in TypeScript that displays a user profile card. It should accept props for 'name' (string), 'email' (string), and 'avatarUrl' (optional string). Include a 'follow' button that toggles between 'Follow' and 'Following' states. Use useState for the toggle state and style with a CSS module.
Example Output:
import React, { useState } from 'react';
import styles from './UserProfileCard.module.css';
interface UserProfileCardProps {
name: string;
email: string;
avatarUrl?: string;
}
const UserProfileCard: React.FC<UserProfileCardProps> = ({ name, email, avatarUrl }) => {
const [isFollowing, setIsFollowing] = useState(false);
return (
<div className={styles.card}>
<img src={avatarUrl || '/default-avatar.png'} alt={name} className={styles.avatar} />
<h2>{name}</h2>
<p>{email}</p>
<button onClick={() => setIsFollowing(!isFollowing)}>
{isFollowing ? 'Following' : 'Follow'}
</button>
</div>
);
};
export default UserProfileCard;
Prompt 2: Type-Safe API Client with Axios
Task: Generate a TypeScript wrapper for a REST API with proper error handling.
Prompt:
Write a TypeScript class that wraps the JSONPlaceholder API using Axios. Include methods for getPosts(), getPost(id: number), and createPost(data: object). Each method should return typed promises. Use a generic type for the response and include a try-catch block that re-throws a custom AppError with status code and message.
Example Output:
import axios, { AxiosError } from 'axios';
interface Post {
userId: number;
id: number;
title: string;
body: string;
}
class AppError extends Error {
statusCode: number;
constructor(message: string, statusCode: number) {
super(message);
this.statusCode = statusCode;
}
}
class ApiClient {
private client = axios.create({ baseURL: 'https://jsonplaceholder.typicode.com' });
async getPosts(): Promise<Post[]> {
try {
const response = await this.client.get<Post[]>('/posts');
return response.data;
} catch (error) {
if (error instanceof AxiosError) {
throw new AppError(error.message, error.response?.status || 500);
}
throw new AppError('Unexpected error', 500);
}
}
async getPost(id: number): Promise<Post> {
try {
const response = await this.client.get<Post>(`/posts/${id}`);
return response.data;
} catch (error) {
if (error instanceof AxiosError) {
throw new AppError(error.message, error.response?.status || 500);
}
throw new AppError('Unexpected error', 500);
}
}
async createPost(data: Omit<Post, 'id'>): Promise<Post> {
try {
const response = await this.client.post<Post>('/posts', data);
return response.data;
} catch (error) {
if (error instanceof AxiosError) {
throw new AppError(error.message, error.response?.status || 500);
}
throw new AppError('Unexpected error', 500);
}
}
}
export default ApiClient;
Prompt 3: Debounce Utility Function
Task: Generate a common utility function with TypeScript generics.
Prompt:
Write a debounce function in TypeScript that takes a function and a delay in milliseconds. The debounced function should cancel previous calls if a new call occurs within the delay. Use generics to preserve the function signature. Include clear type annotations and JSDoc comments.
Example Output:
/**
* Creates a debounced version of the provided function.
* @param fn - The function to debounce.
* @param delay - Delay in milliseconds.
* @returns A debounced function with the same signature.
*/
export function debounce<T extends (...args: any[]) => any>(
fn: T,
delay: number
): (...args: Parameters<T>) => void {
let timeoutId: ReturnType<typeof setTimeout> | null = null;
return (...args: Parameters<T>) => {
if (timeoutId) {
clearTimeout(timeoutId);
}
timeoutId = setTimeout(() => {
fn(...args);
timeoutId = null;
}, delay);
};
}
Prompt 4: Node.js Express Middleware for Authentication
Task: Generate a middleware that verifies a JWT token.
Prompt:
Write an Express middleware in TypeScript that verifies a JWT token from the Authorization header. If the token is valid, attach the decoded payload to req.user. If invalid, return a 401 response. Use the jsonwebtoken library. Define a custom interface for the request to include the user property.
Example Output:
import { Request, Response, NextFunction } from 'express';
import jwt from 'jsonwebtoken';
interface AuthRequest extends Request {
user?: string | object;
}
export const authenticate = (req: AuthRequest, res: Response, next: NextFunction) => {
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith('Bearer ')) {
return res.status(401).json({ message: 'Unauthorized: No token provided' });
}
const token = authHeader.split(' ')[1];
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET || 'default_secret');
req.user = decoded;
next();
} catch (error) {
return res.status(401).json({ message: 'Unauthorized: Invalid token' });
}
};
Prompt 5: Custom React Hook for Fetching Data
Task: Create a reusable hook for API calls with loading and error states.
Prompt:
Generate a custom React hook in TypeScript called useFetch that takes a URL string and returns an object with { data, loading, error }. Use the fetch API and useEffect. The hook should abort the fetch on component unmount using AbortController. Include proper TypeScript generics so the hook can be reused with any data type.
Example Output:
import { useState, useEffect } from 'react';
interface FetchResult<T> {
data: T | null;
loading: boolean;
error: string | null;
}
export function useFetch<T>(url: string): FetchResult<T> {
const [data, setData] = useState<T | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
const controller = new AbortController();
const fetchData = async () => {
setLoading(true);
setError(null);
try {
const response = await fetch(url, { signal: controller.signal });
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
setData(result);
} catch (err) {
if (err instanceof Error && err.name !== 'AbortError') {
setError(err.message);
}
} finally {
setLoading(false);
}
};
fetchData();
return () => controller.abort();
}, [url]);
return { data, loading, error };
}
Prompt 6: Array GroupBy Utility
Task: Write a utility to group an array by a key.
Prompt:
Write a TypeScript utility function groupBy that takes an array of objects and a key extractor function. The function should return a Map where keys are the extracted values and values are arrays of matching objects. Use generics. For example, groupBy([{category:'a'}, {category:'b'}, {category:'a'}], item => item.category) should return Map {'a' => [item1, item3], 'b' => [item2]}.
Example Output:
export function groupBy<T, K>(items: T[], keyFn: (item: T) => K): Map<K, T[]> {
const map = new Map<K, T[]>();
for (const item of items) {
const key = keyFn(item);
const group = map.get(key);
if (group) {
group.push(item);
} else {
map.set(key, [item]);
}
}
return map;
}
Prompt 7: React Context with TypeScript
Task: Generate a typed React context for a theme switcher.
Prompt:
Create a React context in TypeScript for a theme (light/dark). The context should provide a 'theme' value and a 'toggleTheme' function. Create a custom hook useTheme that returns the context. Include a ThemeProvider component. Use proper TypeScript types.
Example Output:
import React, { createContext, useContext, useState, ReactNode } from 'react';
type Theme = 'light' | 'dark';
interface ThemeContextType {
theme: Theme;
toggleTheme: () => void;
}
const ThemeContext = createContext<ThemeContextType | undefined>(undefined);
export const ThemeProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
const [theme, setTheme] = useState<Theme>('light');
const toggleTheme = () => setTheme(prev => (prev === 'light' ? 'dark' : 'light'));
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
};
export const useTheme = (): ThemeContextType => {
const context = useContext(ThemeContext);
if (!context) {
throw new Error('useTheme must be used within a ThemeProvider');
}
return context;
};
Prompt 8: TypeScript Enum with Utility Functions
Task: Generate an enum with helper functions.
Prompt:
Write a TypeScript enum 'HttpStatus' with values OK (200), NotFound (404), and InternalServerError (500). Then create a utility function 'isSuccess' that returns true if the status is between 200 and 299, and a function 'getStatusMessage' that returns a human-readable message for each status. Use a const object instead of enum if you prefer.
Example Output:
export const HttpStatus = {
OK: 200,
NotFound: 404,
InternalServerError: 500,
} as const;
export type HttpStatus = (typeof HttpStatus)[keyof typeof HttpStatus];
export function isSuccess(status: HttpStatus): boolean {
return status >= 200 && status < 300;
}
export function getStatusMessage(status: HttpStatus): string {
switch (status) {
case HttpStatus.OK:
return 'OK';
case HttpStatus.NotFound:
return 'Not Found';
case HttpStatus.InternalServerError:
return 'Internal Server Error';
default:
return 'Unknown Status';
}
}
Prompt 9: Promise-based Sleep Function
Task: Generate an async sleep utility.
Prompt:
Write a TypeScript function 'sleep' that returns a Promise that resolves after a given number of milliseconds. Include a TSDoc comment. Example usage: await sleep(2000).
Example Output:
/**
* Delays execution for the specified number of milliseconds.
* @param ms - Number of milliseconds to wait.
* @returns A Promise that resolves after the delay.
*/
export function sleep(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms));
}
Prompt 10: Form Validation with TypeScript
Task: Generate a form validation function for a login form.
Prompt:
Write a TypeScript validation function for a login form with fields 'email' (string) and 'password' (string). The function should return an object with error messages for each field. Email must be a valid email format, password must be at least 8 characters. Use a simple regex for email validation. Return an empty object if valid.
Example Output:
interface LoginForm {
email: string;
password: string;
}
export function validateLoginForm(form: LoginForm): Partial<Record<keyof LoginForm, string>> {
const errors: Partial<Record<keyof LoginForm, string>> = {};
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!form.email) {
errors.email = 'Email is required';
} else if (!emailRegex.test(form.email)) {
errors.email = 'Invalid email format';
}
if (!form.password) {
errors.password = 'Password is required';
} else if (form.password.length < 8) {
errors.password = 'Password must be at least 8 characters';
}
return errors;
}
Prompt 11: React Event Handler with Debounce
Task: Generate a search input with debounced onChange.
Prompt:
Create a React component in TypeScript that renders an input field. When the user types, after a 300ms delay, call a 'onSearch' prop with the current input value. Use the debounce function from Prompt 3. Include proper event typing.
Example Output:
import React, { useState, useEffect } from 'react';
import { debounce } from './debounce';
interface SearchInputProps {
onSearch: (query: string) => void;
placeholder?: string;
}
const SearchInput: React.FC<SearchInputProps> = ({ onSearch, placeholder = 'Search...' }) => {
const [value, setValue] = useState('');
const debouncedSearch = debounce((query: string) => {
onSearch(query);
}, 300);
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setValue(e.target.value);
debouncedSearch(e.target.value);
};
return (
<input
type="text"
value={value}
onChange={handleChange}
placeholder={placeholder}
/>
);
};
export default SearchInput;
Prompt 12: Node.js File Read/Write Utility
Task: Generate asynchronous file operations with error handling.
Prompt:
Write two TypeScript functions using the fs/promises module: readJsonFile(path: string) that reads a JSON file and parses it, and writeJsonFile(path: string, data: object) that writes a JSON file. Both should handle errors gracefully and return a promise. Use generics for readJsonFile to allow type inference.
Example Output:
import { readFile, writeFile } from 'fs/promises';
export async function readJsonFile<T>(path: string): Promise<T> {
try {
const content = await readFile(path, 'utf-8');
return JSON.parse(content) as T;
} catch (error) {
throw new Error(`Failed to read JSON file: ${error}`);
}
}
export async function writeJsonFile(path: string, data: object): Promise<void> {
try {
await writeFile(path, JSON.stringify(data, null, 2), 'utf-8');
} catch (error) {
throw new Error(`Failed to write JSON file: ${error}`);
}
}
Prompt 13: TypeScript Union Type Guard
Task: Write a type guard for a discriminated union.
Prompt:
Define a discriminated union type 'Shape' that can be 'Circle' (with radius) or 'Square' (with side). Write a type guard function 'isCircle' that narrows the type. Then write a function 'calculateArea' that uses the type guard to compute the area.
Example Output:
interface Circle {
kind: 'circle';
radius: number;
}
interface Square {
kind: 'square';
side: number;
}
type Shape = Circle | Square;
export function isCircle(shape: Shape): shape is Circle {
return shape.kind === 'circle';
}
export function calculateArea(shape: Shape): number {
if (isCircle(shape)) {
return Math.PI * shape.radius ** 2;
} else {
return shape.side ** 2;
}
}
Prompt 14: React List with Key and Empty State
Task: Generate a list component that handles empty and loading states.
Prompt:
Create a React component in TypeScript that renders a list of items. It should accept props: items (array of {id: number, text: string}), loading (boolean), and error (string | null). Display a loading spinner when loading, an error message when error is set, and a 'No items found' message when items is empty. Use a key prop.
Example Output:
import React from 'react';
interface Item {
id: number;
text: string;
}
interface ItemListProps {
items: Item[];
loading: boolean;
error: string | null;
}
const ItemList: React.FC<ItemListProps> = ({ items, loading, error }) => {
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error}</div>;
if (items.length === 0) return <div>No items found.</div>;
return (
<ul>
{items.map(item => (
<li key={item.id}>{item.text}</li>
))}
</ul>
);
};
export default ItemList;
Prompt 15: TypeScript Mapped Type for API Response
Task: Generate a mapped type that transforms all properties to optional.
Prompt:
Write a TypeScript mapped type 'PartialResponse<T>' that makes all properties optional and also adds a 'status' property (string) to the type. Then create a function 'formatResponse' that takes data of type T and returns a PartialResponse<T> with status: 'success'.
Example Output:
type PartialResponse<T> = {
[P in keyof T]?: T[P];
} & { status: string };
export function formatResponse<T>(data: T): PartialResponse<T> {
return { ...data, status: 'success' };
}
// Usage example:
const user = { name: 'Alice', age: 30 };
const response = formatResponse(user);
// response type: { name?: string; age?: number; status: string }
Prompt 16: Async Queue with Concurrency Limit
Task: Generate a queue that limits concurrent async tasks.
Prompt:
Write a TypeScript class 'AsyncQueue' that takes a concurrency limit (number). It should have an 'add' method that accepts a function returning a Promise. The queue should execute up to 'limit' tasks concurrently. When a task completes, the next queued task should start. Return a promise from 'add' that resolves with the task result.
Example Output:
export class AsyncQueue {
private queue: (() => Promise<any>)[] = [];
private activeCount = 0;
private limit: number;
constructor(limit: number) {
this.limit = limit;
}
add<T>(task: () => Promise<T>): Promise<T> {
return new Promise<T>((resolve, reject) => {
const runTask = async () => {
this.activeCount++;
try {
const result = await task();
resolve(result);
} catch (error) {
reject(error);
} finally {
this.activeCount--;
this.dequeue();
}
};
if (this.activeCount < this.limit) {
runTask();
} else {
this.queue.push(runTask);
}
});
}
private dequeue(): void {
if (this.queue.length > 0 && this.activeCount < this.limit) {
const nextTask = this.queue.shift();
if (nextTask) nextTask();
}
}
}
Prompt 17: React Custom Hook for LocalStorage
Task: Generate a hook that syncs state with localStorage.
Prompt:
Write a custom React hook in TypeScript 'useLocalStorage' that takes a key (string) and initial value. It should store the value in localStorage and update it on changes. Use JSON serialization. Return a tuple [value, setValue] similar to useState. Handle the case where the stored data is corrupted (parse error) by falling back to initial value.
Example Output:
import { useState, useEffect } from 'react';
export function useLocalStorage<T>(key: string, initialValue: T): [T, (value: T | ((prev: T) => T)) => void] {
const [storedValue, setStoredValue] = useState<T>(() => {
try {
const item = window.localStorage.getItem(key);
return item ? (JSON.parse(item) as T) : initialValue;
} catch (error) {
console.error('Error reading localStorage key', key, error);
return initialValue;
}
});
const setValue = (value: T | ((prev: T) => T)) => {
setStoredValue(prev => {
const valueToStore = value instanceof Function ? value(prev) : value;
try {
window.localStorage.setItem(key, JSON.stringify(valueToStore));
} catch (error) {
console.error('Error setting localStorage key', key, error);
}
return valueToStore;
});
};
return [storedValue, setValue];
}
Prompt 18: TypeScript Conditional Type for Function Return
Task: Generate a conditional type that extracts the return type of a function.
Prompt:
Write a conditional type 'ReturnTypeOf<T>' that, if T is a function, evaluates to its return type, otherwise to never. Then create a helper function 'getReturnType' that takes a function and returns a dummy value of that type (for type inference purposes). Use the built-in ReturnType utility as a reference.
Example Output:
type ReturnTypeOf<T> = T extends (...args: any[]) => infer R ? R : never;
export function getReturnType<T extends (...args: any[]) => any>(fn: T): ReturnTypeOf<T> {
// This is just for type inference — no runtime value needed.
return undefined as unknown as ReturnTypeOf<T>;
}
// Usage example:
const fn = (x: number) => x.toString();
type Result = ReturnTypeOf<typeof fn>; // string
Prompt 19: Node.js Simple HTTP Server
Task: Generate a basic HTTP server with routing.
Prompt:
Write a simple HTTP server in Node.js using the built-in 'http' module. It should handle two routes: GET / and GET /data. The root route returns a plain text message. The /data route returns a JSON object {message: 'Hello from server'}. Use TypeScript and include proper request/response typing. Handle 404 for unknown routes.
Example Output:
import http, { IncomingMessage, ServerResponse } from 'http';
const server = http.createServer((req: IncomingMessage, res: ServerResponse) => {
const { url, method } = req;
if (method === 'GET' && url === '/') {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Welcome to the server!');
} else if (method === 'GET' && url === '/data') {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ message: 'Hello from server' }));
} else {
res.writeHead(404, { 'Content-Type': 'text/plain' });
res.end('Not Found');
}
});
const PORT = 3000;
server.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});
Prompt 20: React Component with Error Boundary
Task: Generate an error boundary component in TypeScript.
Prompt:
Create a React error boundary component in TypeScript using class component syntax. It should catch JavaScript errors anywhere in its child component tree, log those errors, and display a fallback UI (a message 'Something went wrong' with a 'Try again' button that resets the error state). Include proper typing for error and errorInfo.
Example Output:
import React, { ErrorInfo, ReactNode } from 'react';
interface ErrorBoundaryProps {
children: ReactNode;
}
interface ErrorBoundaryState {
hasError: boolean;
}
class ErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {
constructor(props: ErrorBoundaryProps) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(_: Error): ErrorBoundaryState {
return { hasError: true };
}
componentDidCatch(error: Error, errorInfo: ErrorInfo): void {
console.error('Error caught by boundary:', error, errorInfo);
}
handleReset = () => {
this.setState({ hasError: false });
};
render() {
if (this.state.hasError) {
return (
<div>
<h1>Something went wrong.</h1>
<button onClick={this.handleReset}>Try again</button>
</div>
);
}
return this.props.children;
}
}
export default ErrorBoundary;
Conclusion
These 20 prompts cover a wide range of everyday tasks for JavaScript and TypeScript developers — from React components and hooks to Node.js utilities and advanced TypeScript types. By using specific, well-structured prompts, you can dramatically reduce the time spent on boilerplate code and focus on solving actual business problems.
The key to effective code generation is clarity: include type information, specify edge cases (like empty states or error handling), and provide concrete examples in the prompt. As AI tools continue to evolve in 2026, writing good prompts is becoming a core skill for every developer. Experiment with these prompts, adapt them to your own codebase, and you will find that AI becomes a reliable pair programmer rather than just a toy.
Comments