12 Prompts for JavaScript and TypeScript Code Generation

Introduction

In modern web development, JavaScript and TypeScript are the backbone of nearly every application — from frontend frameworks like React to backend services running on Node.js. However, writing repetitive boilerplate, complex state management logic, or type-safe utilities can slow down even experienced developers. AI-powered code generation, using well-crafted prompts, can dramatically accelerate your workflow by producing production-ready snippets, components, and functions in seconds.

This collection of 12 practical prompts is designed for developers who want to leverage AI tools (like ChatGPT, Claude, or GitHub Copilot) to generate high-quality JavaScript and TypeScript code. Each prompt is specific, copy-paste ready, and includes a real-world usage example with code. Whether you are building React components, Node.js APIs, or utility functions, these prompts will save you time and reduce boilerplate.

1. React Functional Component with TypeScript Props

Task: Generate a reusable React component with typed props, default values, and event handlers.

Prompt:

Generate a React functional component in TypeScript that displays a user profile card. The component should accept props: `name` (string, required), `email` (string, required), `avatarUrl` (string, optional), and `onEdit` (function, optional). Include a default avatar if none provided, and a button to trigger the onEdit callback. Use React.FC type and include JSDoc comments.

Usage Example:

import React from 'react';

interface UserProfileCardProps {
  name: string;
  email: string;
  avatarUrl?: string;
  onEdit?: () => void;
}

const UserProfileCard: React.FC<UserProfileCardProps> = ({
  name,
  email,
  avatarUrl = 'https://via.placeholder.com/150',
  onEdit,
}) => {
  return (
    <div className=\"profile-card\">
      <img src={avatarUrl} alt={name} />
      <h2>{name}</h2>
      <p>{email}</p>
      {onEdit && <button onClick={onEdit}>Edit</button>}
    </div>
  );
};

export default UserProfileCard;

2. Custom React Hook for API Fetching

Task: Create a reusable hook that handles data fetching with loading and error states.

Prompt:

Write a custom React hook in TypeScript called `useFetch` that takes a URL string and returns an object with `data`, `loading`, and `error` states. Use the fetch API, handle abort on unmount, and parse JSON. Include a generic type parameter for the response data.

Usage Example:

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<boolean>(true);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    const abortController = new AbortController();
    const fetchData = async () => {
      try {
        setLoading(true);
        const response = await fetch(url, { signal: abortController.signal });
        if (!response.ok) throw new Error('Network error');
        const result: T = await response.json();
        setData(result);
      } catch (err) {
        if (err instanceof Error && err.name !== 'AbortError') {
          setError(err.message);
        }
      } finally {
        setLoading(false);
      }
    };
    fetchData();
    return () => abortController.abort();
  }, [url]);

  return { data, loading, error };
}

3. Node.js Express Middleware for Authentication

Task: Generate a JWT-based authentication middleware for Express.js in TypeScript.

Prompt:

Create an Express middleware function in TypeScript that verifies a JWT token from the Authorization header (Bearer scheme). If valid, attach the decoded user payload to `req.user` and call next(). If invalid or missing, return 401 with an error message. Use jsonwebtoken library and define a custom Request interface.

Usage Example:

import { Request, Response, NextFunction } from 'express';
import jwt from 'jsonwebtoken';

interface AuthRequest extends Request {
  user?: { id: string; email: string };
}

export const authenticate = (req: AuthRequest, res: Response, next: NextFunction): void => {
  const authHeader = req.headers.authorization;
  if (!authHeader || !authHeader.startsWith('Bearer ')) {
    res.status(401).json({ error: 'Missing or invalid token' });
    return;
  }

  const token = authHeader.split(' ')[1];
  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET as string) as { id: string; email: string };
    req.user = decoded;
    next();
  } catch (err) {
    res.status(401).json({ error: 'Token expired or invalid' });
  }
};

4. TypeScript Utility Type: Deep Partial

Task: Write a utility type that makes all nested properties optional recursively.

Prompt:

Define a TypeScript utility type called `DeepPartial<T>` that makes every property of an object (including nested objects) optional. Use recursive conditional types. Then demonstrate with a nested User interface.

Usage Example:

type DeepPartial<T> = {
  [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
};

interface User {
  id: number;
  profile: {
    name: string;
    address: {
      street: string;
      city: string;
    };
  };
}

const partialUser: DeepPartial<User> = {
  profile: {
    address: { city: 'New York' },
  },
};

5. React Form with Validation (No Library)

Task: Build a simple login form component with email and password validation using React state.

Prompt:

Write a React functional component in TypeScript for a login form with fields `email` and `password`. Validate email format with regex, require password at least 6 characters. Show error messages below each field. On submit, call an `onLogin` prop with the form data. Use useState for form state.

Usage Example:

import React, { useState } from 'react';

interface LoginFormData {
  email: string;
  password: string;
}

interface LoginFormProps {
  onLogin: (data: LoginFormData) => void;
}

const LoginForm: React.FC<LoginFormProps> = ({ onLogin }) => {
  const [form, setForm] = useState<LoginFormData>({ email: '', password: '' });
  const [errors, setErrors] = useState<Partial<LoginFormData>>({});

  const validate = (): boolean => {
    const newErrors: Partial<LoginFormData> = {};
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (!emailRegex.test(form.email)) newErrors.email = 'Invalid email';
    if (form.password.length < 6) newErrors.password = 'Password must be at least 6 characters';
    setErrors(newErrors);
    return Object.keys(newErrors).length === 0;
  };

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    if (validate()) onLogin(form);
  };

  return (
    <form onSubmit={handleSubmit}>
      <div>
        <input
          type="email"
          value={form.email}
          onChange={(e) => setForm({ ...form, email: e.target.value })}
        />
        {errors.email && <span>{errors.email}</span>}
      </div>
      <div>
        <input
          type="password"
          value={form.password}
          onChange={(e) => setForm({ ...form, password: e.target.value })}
        />
        {errors.password && <span>{errors.password}</span>}
      </div>
      <button type="submit">Login</button>
    </form>
  );
};

export default LoginForm;

6. Debounce Utility Function

Task: Write a generic debounce function with TypeScript types.

Prompt:

Create a debounce function in TypeScript that takes a callback function and a delay in milliseconds. Return a debounced version that only calls the original after the delay has passed since the last invocation. Use generics to preserve the function signature.

Usage Example:

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), delay);
  };
}

// Usage
const log = (msg: string) => console.log(msg);
const debouncedLog = debounce(log, 300);
debouncedLog('Hello'); // Only fires after 300ms

7. React Context with TypeScript

Task: Create a typed React context for a theme (light/dark) with a provider and hook.

Prompt:

Generate a React context in TypeScript for managing a theme. Include a `ThemeProvider` component that wraps children and provides `theme` (string) and `toggleTheme` function. Export a custom hook `useTheme` that throws an error if used outside provider.

Usage Example:

import React, { createContext, useContext, useState, ReactNode } from 'react';

interface ThemeContextType {
  theme: string;
  toggleTheme: () => void;
}

const ThemeContext = createContext<ThemeContextType | undefined>(undefined);

export const ThemeProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
  const [theme, setTheme] = useState<string>('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;
};

8. Node.js File Upload Handler (Multer)

Task: Write an Express route for single file upload with Multer and TypeScript.

Prompt:

Create an Express route handler in TypeScript that accepts a single file upload using Multer. Configure Multer to store files in a 'uploads/' directory with a unique filename (timestamp + original name). Limit file size to 5MB. Return the filename and path on success.

Usage Example:

import multer from 'multer';
import path from 'path';
import { Request, Response } from 'express';

const storage = multer.diskStorage({
  destination: './uploads/',
  filename: (req, file, cb) => {
    const uniqueName = Date.now() + '-' + file.originalname;
    cb(null, uniqueName);
  },
});

const upload = multer({
  storage,
  limits: { fileSize: 5 * 1024 * 1024 },
});

export const uploadFile = (req: Request, res: Response): void => {
  upload.single('file')(req, res, (err) => {
    if (err) {
      res.status(400).json({ error: err.message });
      return;
    }
    if (!req.file) {
      res.status(400).json({ error: 'No file uploaded' });
      return;
    }
    res.json({ filename: req.file.filename, path: req.file.path });
  });
};

9. TypeScript Enum with Mapping Object

Task: Generate an enum for HTTP status codes and a mapping object for descriptions.

Prompt:

Define a TypeScript enum for common HTTP status codes (200, 201, 400, 401, 404, 500). Then create a const object that maps each status code to a human-readable description. Write a helper function that returns the description given a status code.

Usage Example:

enum HttpStatus {
  OK = 200,
  Created = 201,
  BadRequest = 400,
  Unauthorized = 401,
  NotFound = 404,
  InternalServerError = 500,
}

const statusDescriptions: Record<HttpStatus, string> = {
  [HttpStatus.OK]: 'Request succeeded',
  [HttpStatus.Created]: 'Resource created',
  [HttpStatus.BadRequest]: 'Invalid request',
  [HttpStatus.Unauthorized]: 'Authentication required',
  [HttpStatus.NotFound]: 'Resource not found',
  [HttpStatus.InternalServerError]: 'Server error',
};

export function getStatusDescription(code: number): string {
  return statusDescriptions[code as HttpStatus] || 'Unknown status';
}

10. React List with Pagination (Client-Side)

Task: Build a paginated list component that slices an array of items.

Prompt:

Write a React component in TypeScript that takes an array of items and renders them in a paginated list. Accept props: `items` (array of any), `pageSize` (number, default 10). Show page numbers, next/prev buttons. Use useState for current page.

Usage Example:

import React, { useState } from 'react';

interface PaginatedListProps<T> {
  items: T[];
  pageSize?: number;
  renderItem: (item: T) => React.ReactNode;
}

export function PaginatedList<T>({ items, pageSize = 10, renderItem }: PaginatedListProps<T>) {
  const [currentPage, setCurrentPage] = useState(1);
  const totalPages = Math.ceil(items.length / pageSize);
  const startIndex = (currentPage - 1) * pageSize;
  const currentItems = items.slice(startIndex, startIndex + pageSize);

  return (
    <div>
      {currentItems.map((item, index) => (
        <div key={index}>{renderItem(item)}</div>
      ))}
      <div>
        <button disabled={currentPage === 1} onClick={() => setCurrentPage((p) => p - 1)}>
          Prev
        </button>
        <span> Page {currentPage} of {totalPages} </span>
        <button disabled={currentPage === totalPages} onClick={() => setCurrentPage((p) => p + 1)}>
          Next
        </button>
      </div>
    </div>
  );
}

11. TypeScript Mapped Type: Readonly Nested

Task: Create a recursive ReadonlyDeep utility type.

Prompt:

Define a TypeScript type called `ReadonlyDeep<T>` that makes all properties (including nested objects and arrays) readonly. Use recursive types with conditional checks for arrays and objects.

Usage Example:

type ReadonlyDeep<T> = T extends object
  ? T extends Array<infer U>
    ? ReadonlyArray<ReadonlyDeep<U>>
    : { readonly [P in keyof T]: ReadonlyDeep<T[P]> }
  : T;

interface Config {
  api: {
    url: string;
    port: number;
  };
  features: string[];
}

const config: ReadonlyDeep<Config> = {
  api: { url: 'https://api.example.com', port: 8080 },
  features: ['auth'],
};
// config.api.url = 'new'; // Error: readonly

12. Node.js Async Error Wrapper

Task: Write a utility function that wraps async Express route handlers to catch errors.

Prompt:

Create a TypeScript function `asyncHandler` that takes an async Express middleware function (Request, Response, NextFunction) and returns a new middleware that catches any rejected promise and passes the error to the next() function. Use generic types.

Usage Example:

import { Request, Response, NextFunction } from 'express';

type AsyncMiddleware = (req: Request, res: Response, next: NextFunction) => Promise<void>;

export const asyncHandler = (fn: AsyncMiddleware) => {
  return (req: Request, res: Response, next: NextFunction): void => {
    Promise.resolve(fn(req, res, next)).catch(next);
  };
};

// Usage in route
import { Router } from 'express';
const router = Router();

router.get(
  '/data',
  asyncHandler(async (req, res) => {
    const data = await fetchData();
    res.json(data);
  })
);

Conclusion

These 12 prompts cover the most common scenarios in JavaScript and TypeScript development: React components, custom hooks, Node.js middleware, utility types, and more. By using these ready-to-use prompts, you can generate production-quality code in seconds, reduce boilerplate, and focus on the unique logic of your application. Copy the prompts above, adapt them to your specific needs, and integrate them into your daily workflow. Experiment with variations — tweak the requirements, add error handling, or combine prompts to build more complex solutions.

Start using these prompts today to accelerate your development process. Bookmark this page for quick reference, and share it with your team to boost productivity across your projects.

← All posts

Comments