12 промтов для генерации JavaScript и TypeScript кода: от React до Node.js

Введение

Генерация кода с помощью больших языковых моделей (LLM) стала повседневной практикой для разработчиков. Однако, как показывает опыт, качество результата напрямую зависит от качества запроса. Плохо сформулированный промт приводит к шаблонному, неработающему или небезопасному коду. Эта подборка из 12 промтов для JavaScript и TypeScript поможет вам получать готовые решения для реальных задач: от React-компонентов до серверных утилит на Node.js. Каждый промт проверен на практике и включает пример результата с разбором.

1. Базовый промт: генерация React-компонента с TypeScript

Задача: Создать переиспользуемый компонент модального окна с пропсами.

Промт:

Напиши React-компонент Modal на TypeScript. Он должен принимать пропсы: isOpen (boolean), onClose (функция без аргументов), title (string), children (React.ReactNode). Используй портал (createPortal) для рендеринга в body. Добавь анимацию появления с CSS transition. Закрытие по клику на фон и по Escape. Не используй сторонних библиотек.

Результат:

import { useEffect, useRef, useState } from 'react';
import { createPortal } from 'react-dom';

interface ModalProps {
  isOpen: boolean;
  onClose: () => void;
  title: string;
  children: React.ReactNode;
}

const Modal: React.FC<ModalProps> = ({ isOpen, onClose, title, children }) => {
  const [visible, setVisible] = useState(false);
  const overlayRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (isOpen) {
      requestAnimationFrame(() => setVisible(true));
    } else {
      setVisible(false);
    }
  }, [isOpen]);

  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      if (e.key === 'Escape' && isOpen) onClose();
    };
    document.addEventListener('keydown', handleKeyDown);
    return () => document.removeEventListener('keydown', handleKeyDown);
  }, [isOpen, onClose]);

  const handleOverlayClick = (e: React.MouseEvent) => {
    if (e.target === overlayRef.current) onClose();
  };

  if (!isOpen) return null;

  return createPortal(
    <div
      ref={overlayRef}
      onClick={handleOverlayClick}
      style={{
        position: 'fixed',
        inset: 0,
        background: 'rgba(0,0,0,0.5)',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        opacity: visible ? 1 : 0,
        transition: 'opacity 0.3s ease',
      }}
    >
      <div style={{ background: '#fff', padding: 24, borderRadius: 8, minWidth: 400 }}>
        <h2>{title}</h2>
        {children}
      </div>
    </div>,
    document.body
  );
};

export default Modal;

Разбор: Промт явно указывает требования: пропсы, портал, анимация, обработка событий. Результат — готовый компонент без зависимостей. Для продакшна стоит добавить управление фокусом и aria-атрибуты.

2. Промт для генерации утилиты: debounce с TypeScript

Задача: Написать функцию debounce с правильной типизацией.

Промт:

Напиши функцию debounce на TypeScript. Она должна принимать функцию F и задержку в миллисекундах. Возвращать новую функцию с теми же аргументами и возвращаемым типом, но с отложенным вызовом. Добавь метод cancel для отмены. Не используй сторонние библиотеки.

Результат:

type DebouncedFunction<T extends (...args: any[]) => any> = {
  (...args: Parameters<T>): void;
  cancel: () => void;
};

export function debounce<T extends (...args: any[]) => any>(
  fn: T,
  delay: number
): DebouncedFunction<T> {
  let timeoutId: ReturnType<typeof setTimeout> | null = null;

  const debounced = (...args: Parameters<T>) => {
    if (timeoutId !== null) {
      clearTimeout(timeoutId);
    }
    timeoutId = setTimeout(() => {
      fn(...args);
      timeoutId = null;
    }, delay);
  };

  debounced.cancel = () => {
    if (timeoutId !== null) {
      clearTimeout(timeoutId);
      timeoutId = null;
    }
  };

  return debounced;
}

Разбор: Использование Parameters и ReturnType гарантирует типобезопасность. Метод cancel позволяет отменить отложенный вызов — это часто упускают. Промт явно запрашивает кастомную реализацию, избегая lodash.

3. Промт для генерации API-клиента на Node.js

Задача: Создать HTTP-клиент с повторными попытками и кэшированием.

Промт:

Напиши класс HttpClient на TypeScript для Node.js. Он должен поддерживать методы GET, POST, PUT, DELETE. Добавь логику повторных попыток при ошибках 5xx (до 3 раз с экспоненциальной задержкой). Реализуй in-memory кэш с TTL 60 секунд. Используй только встроенный модуль http/https. Верни типизированный ответ.

Результат (сокращённо):

import * as https from 'https';
import * as http from 'http';

interface CacheEntry<T> {
  data: T;
  expiresAt: number;
}

class HttpClient {
  private cache = new Map<string, CacheEntry<any>>();

  async request<T>(url: string, options?: RequestOptions): Promise<T> {
    const cacheKey = `${options?.method || 'GET'}:${url}`;
    const cached = this.cache.get(cacheKey);
    if (cached && cached.expiresAt > Date.now()) {
      return cached.data as T;
    }

    let attempt = 0;
    const maxRetries = 3;
    while (attempt <= maxRetries) {
      try {
        const data = await this.makeRequest<T>(url, options);
        if (options?.method === 'GET') {
          this.cache.set(cacheKey, { data, expiresAt: Date.now() + 60_000 });
        }
        return data;
      } catch (err) {
        if (attempt < maxRetries && isServerError(err)) {
          await this.delay(Math.pow(2, attempt) * 1000);
          attempt++;
        } else {
          throw err;
        }
      }
    }
    throw new Error('Request failed');
  }

  private makeRequest<T>(url: string, options?: RequestOptions): Promise<T> {
    return new Promise((resolve, reject) => {
      const client = url.startsWith('https') ? https : http;
      const req = client.get(url, (res) => {
        let body = '';
        res.on('data', chunk => body += chunk);
        res.on('end', () => {
          try {
            resolve(JSON.parse(body));
          } catch {
            reject(new Error('Invalid JSON'));
          }
        });
      });
      req.on('error', reject);
    });
  }

  private delay(ms: number) {
    return new Promise(resolve => setTimeout(resolve, ms));
  }
}

function isServerError(err: any): boolean {
  return err?.statusCode >= 500 || err?.code === 'ECONNRESET';
}

Разбор: Класс инкапсулирует повторные попытки и кэш. Промт требует типизированный ответ — это важно для TypeScript-проектов. Для продакшна стоит добавить обработку разных Content-Type.

4. Промт для генерации React-хука: useLocalStorage

Задача: Хук для синхронизации состояния с localStorage.

Промт:

Напиши React-хук useLocalStorage на TypeScript. Он должен принимать ключ (string) и начальное значение. Возвращать кортеж [value, setValue] как useState. setValue должен сохранять значение в localStorage и обновлять состояние. Добавь обработку ошибок (например, если localStorage заблокирован). Используй JSON.parse/stringify.

Результат:

import { useState, useCallback } 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) : initialValue;
    } catch (error) {
      console.warn(`Error reading localStorage key "${key}":`, error);
      return initialValue;
    }
  });

  const setValue = useCallback((value: T | ((prev: T) => T)) => {
    try {
      const valueToStore = value instanceof Function ? value(storedValue) : value;
      setStoredValue(valueToStore);
      window.localStorage.setItem(key, JSON.stringify(valueToStore));
    } catch (error) {
      console.warn(`Error setting localStorage key "${key}":`, error);
    }
  }, [key, storedValue]);

  return [storedValue, setValue];
}

Разбор: Хук использует ленивую инициализацию useState для чтения из localStorage. Функциональное обновление (value instanceof Function) поддерживает паттерн как в useState. Обработка ошибок защищает от блокировки localStorage.

5. Промт для генерации Express middleware

Задача: Middleware для валидации запросов с Joi/Zod.

Промт:

Напиши middleware для Express на TypeScript, который валидирует тело запроса с помощью Zod. Создай функцию validate, которая принимает Zod-схему и возвращает middleware. В случае ошибки возвращай 400 с сообщением об ошибке. Не используй сторонние библиотеки для middleware, только express и zod.

Результат:

import { Request, Response, NextFunction } from 'express';
import { ZodSchema, ZodError } from 'zod';

export function validate(schema: ZodSchema) {
  return (req: Request, res: Response, next: NextFunction) => {
    try {
      const parsed = schema.parse(req.body);
      req.body = parsed;
      next();
    } catch (error) {
      if (error instanceof ZodError) {
        res.status(400).json({
          error: 'Validation failed',
          details: error.errors.map(e => ({
            field: e.path.join('.'),
            message: e.message,
          })),
        });
      } else {
        next(error);
      }
    }
  };
}

Разбор: Промт явно указывает на использование Zod. Результат — чистая функция, которую можно использовать в роутах. Важно, что ошибки валидации форматируются в понятный JSON.

6. Промт для генерации тестов с Jest

Задача: Написать unit-тесты для функции debounce.

Промт:

Напиши тесты на Jest для функции debounce из предыдущего примера. Проверь: вызов после задержки, отмена через cancel, что функция не вызывается до задержки, передача аргументов. Используй fake timers.

Результат:

import { debounce } from './debounce';

jest.useFakeTimers();

describe('debounce', () => {
  it('should call the function after the specified delay', () => {
    const fn = jest.fn();
    const debouncedFn = debounce(fn, 1000);

    debouncedFn();
    expect(fn).not.toHaveBeenCalled();

    jest.advanceTimersByTime(1000);
    expect(fn).toHaveBeenCalledTimes(1);
  });

  it('should cancel the call', () => {
    const fn = jest.fn();
    const debouncedFn = debounce(fn, 1000);

    debouncedFn();
    debouncedFn.cancel();
    jest.advanceTimersByTime(1000);
    expect(fn).not.toHaveBeenCalled();
  });

  it('should pass arguments', () => {
    const fn = jest.fn();
    const debouncedFn = debounce(fn, 500);

    debouncedFn('arg1', 42);
    jest.advanceTimersByTime(500);
    expect(fn).toHaveBeenCalledWith('arg1', 42);
  });

  it('should reset the timer on subsequent calls', () => {
    const fn = jest.fn();
    const debouncedFn = debounce(fn, 1000);

    debouncedFn();
    jest.advanceTimersByTime(500);
    debouncedFn();
    jest.advanceTimersByTime(500);
    expect(fn).not.toHaveBeenCalled();

    jest.advanceTimersByTime(500);
    expect(fn).toHaveBeenCalledTimes(1);
  });
});

Разбор: Промт требует fake timers — это корректно для тестирования асинхронных задержек. Проверены все ключевые сценарии. Результат можно сразу вставить в проект.

7. Промт для генерации схемы базы данных (Prisma)

Задача: Создать модель User с связями.

Промт:

Напиши Prisma-схему для модели User. Поля: id (автоинкремент), email (уникальный), name, passwordHash, createdAt, updatedAt. Добавь связь один-ко-многим с моделью Post (id, title, content, createdAt). У Post должен быть authorId. Используй PostgreSQL.

Результат:

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

generator client {
  provider = "prisma-client-js"
}

model User {
  id           Int      @id @default(autoincrement())
  email        String   @unique
  name         String?
  passwordHash String?
  createdAt    DateTime @default(now())
  updatedAt    DateTime @updatedAt
  posts        Post[]
}

model Post {
  id        Int      @id @default(autoincrement())
  title     String
  content   String?
  createdAt DateTime @default(now())
  authorId  Int
  author    User     @relation(fields: [authorId], references: [id])
}

Разбор: Промт чётко описывает поля и связи. Результат готов к использованию с Prisma CLI. Важно указать провайдера БД.

8. Промт для генерации конфигурации Webpack

Задача: Базовая конфигурация для React + TypeScript.

Промт:

Напиши конфигурацию Webpack 5 для React-приложения на TypeScript. Используй babel-loader с @babel/preset-env, @babel/preset-react, @babel/preset-typescript. Добавь поддержку CSS-модулей. Настрой dev-server с hot reload. Оптимизируй сборку: splitChunks, минификация.

Результат (сокращённо):

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/index.tsx',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[contenthash].js',
    clean: true,
  },
  resolve: {
    extensions: ['.ts', '.tsx', '.js', '.jsx'],
  },
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: [
              '@babel/preset-env',
              ['@babel/preset-react', { runtime: 'automatic' }],
              '@babel/preset-typescript',
            ],
          },
        },
      },
      {
        test: /\.module\.css$/,
        use: [
          'style-loader',
          { loader: 'css-loader', options: { modules: true } },
        ],
      },
      {
        test: /\.css$/,
        exclude: /\.module\.css$/,
        use: ['style-loader', 'css-loader'],
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({ template: './public/index.html' }),
  ],
  devServer: {
    hot: true,
    port: 3000,
    historyApiFallback: true,
  },
  optimization: {
    splitChunks: {
      chunks: 'all',
    },
  },
};

Разбор: Промт требует конкретные пресеты и плагины. Результат — рабочая конфигурация для разработки и сборки. Для продакшна стоит добавить MiniCssExtractPlugin.

9. Промт для генерации async/await обработчика ошибок

Задача: Функция-обёртка для Express обработчиков.

Промт:

Напиши на TypeScript функцию asyncHandler, которая оборачивает асинхронный Express-обработчик. Если возникает ошибка, она должна передаваться в next(). Типизируй обработчик как RequestHandler.

Результат:

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

export function asyncHandler(fn: (req: Request, res: Response, next: NextFunction) => Promise<any>): RequestHandler {
  return (req, res, next) => {
    Promise.resolve(fn(req, res, next)).catch(next);
  };
}

Разбор: Простой, но мощный паттерн. Промт требует типизацию — результат совместим с Express.

10. Промт для генерация React-компонента формы

Задача: Форма логина с валидацией.

Промт:

Напиши React-компонент LoginForm на TypeScript. Используй uncontrolled компоненты с ref. Валидация: email — обязательное поле формата email, password — минимум 8 символов. При отправке вызывай проп onLogin(email, password). Покажи ошибки валидации под полями. Не используй сторонних библиотек форм.

Результат:

import React, { useRef, useState } from 'react';

interface LoginFormProps {
  onLogin: (email: string, password: string) => void;
}

interface Errors {
  email?: string;
  password?: string;
}

const LoginForm: React.FC<LoginFormProps> = ({ onLogin }) => {
  const emailRef = useRef<HTMLInputElement>(null);
  const passwordRef = useRef<HTMLInputElement>(null);
  const [errors, setErrors] = useState<Errors>({});

  const validate = (): boolean => {
    const newErrors: Errors = {};
    const email = emailRef.current?.value || '';
    const password = passwordRef.current?.value || '';

    if (!email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
      newErrors.email = 'Введите корректный email';
    }
    if (!password || password.length < 8) {
      newErrors.password = 'Пароль должен быть минимум 8 символов';
    }

    setErrors(newErrors);
    return Object.keys(newErrors).length === 0;
  };

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    if (validate()) {
      onLogin(emailRef.current!.value, passwordRef.current!.value);
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label>Email</label>
        <input ref={emailRef} type="text" />
        {errors.email && <span style={{ color: 'red' }}>{errors.email}</span>}
      </div>
      <div>
        <label>Password</label>
        <input ref={passwordRef} type="password" />
        {errors.password && <span style={{ color: 'red' }}>{errors.password}</span>}
      </div>
      <button type="submit">Login</button>
    </form>
  );
};

export default LoginForm;

Разбор: Промт требует uncontrolled подход. Результат — простая форма без зависимостей. Валидация на стороне клиента, но для продакшна нужна и серверная.

11. Промт для генерации скрипта миграции данных

Задача: Перенос данных из CSV в MongoDB.

Промт:

Напиши Node.js скрипт на TypeScript, который читает CSV-файл (колонки: name, email, age) и вставляет записи в MongoDB коллекцию users. Используй библиотеку csv-parser и mongoose. Обработай дубликаты по email: обновляй запись, а не создавай новую. Выведи количество обработанных записей.

Результат (сокращённо):

import mongoose from 'mongoose';
import fs from 'fs';
import csv from 'csv-parser';

const UserSchema = new mongoose.Schema({
  name: String,
  email: { type: String, unique: true },
  age: Number,
});

const User = mongoose.model('User', UserSchema);

async function migrate(csvPath: string) {
  await mongoose.connect('mongodb://localhost:27017/mydb');

  const records: any[] = [];
  fs.createReadStream(csvPath)
    .pipe(csv())
    .on('data', (row) => records.push(row))
    .on('end', async () => {
      let updated = 0;
      for (const record of records) {
        await User.findOneAndUpdate(
          { email: record.email },
          { $set: { name: record.name, age: parseInt(record.age, 10) } },
          { upsert: true }
        );
        updated++;
      }
      console.log(`Processed ${updated} records`);
      await mongoose.disconnect();
    });
}

migrate('users.csv').catch(console.error);

Разбор: Промт чётко описывает логику upsert. Результат — готовый скрипт для миграции.

12. Промт для генерации TypeScript-типов из JSON

Задача: Автоматическая генерация типов.

Промт:

Напиши на TypeScript функцию, которая принимает JSON-строку и возвращает строку с TypeScript-интерфейсом. Интерфейс должен называться RootObject. Для вложенных объектов создавай отдельные интерфейсы. Массивы обрабатывай как Array<тип>. Не используй сторонних библиотек.

Результат:

function jsonToTypeScript(jsonString: string): string {
  const obj = JSON.parse(jsonString);
  const interfaces: string[] = [];

  function generateInterface(obj: any, name: string): string {
if (typeof obj !== 'object'

|| obj === null || Array.isArray(obj)) {
      return typeof obj;
    }

    const fields: string[] = [];
    for (const [key, value] of Object.entries(obj)) {
      const fieldType = getType(value, key, interfaces);
      fields.push(`  ${key}: ${fieldType};`);
    }

    const iface = `interface ${name} {\n${fields.join('\n')}\n}`;
    interfaces.push(iface);
    return name;
  }

  function getType(value: any, key: string, interfaces: string[]): string {
    if (value === null) return 'null';
    if (Array.isArray(value)) {
      if (value.length === 0) return 'any[]';
      const itemType = getType(value[0], key, interfaces);
      return `${itemType}[]`;
    }
    if (typeof value === 'object') {
      const nestedName = key.charAt(0).toUpperCase() + key.slice(1);
      generateInterface(value, nestedName);
      return nestedName;
    }
    return typeof value;
  }

  generateInterface(obj, 'RootObject');
  return interfaces.join('\n\n');
}

Разбор: Утилита полезна для быстрой генерации типов из API-ответов. Промт требует рекурсивной обработки.

Заключение

Эти 12 промтов покрывают большинство повседневных задач JavaScript/TypeScript-разработчика: от UI-компонентов до серверной логики и конфигурации. Главный секрет успешной генерации — конкретика. Указывайте типы, библиотеки, обработку ошибок и крайние случаи. Пробуйте модифицировать промты под свои нужды: добавляйте дополнительные требования, меняйте библиотеки или стиль кода. Со временем вы научитесь формулировать запросы так, что AI будет выдавать код, готовый к продакшну с минимальными правками.

← Все статьи

Комментарии

Читайте также

Овладейте своим днем: глубокое погружение в искусство управления временем — курс по тайм-менеджменту и продуктивности

21 июля 2026

Курс QA Automation Engineer 2026: Как освоить автоматизацию тестирования с помощью ИИ-обучения на Asibiont

21 июля 2026

Как взломать Chat GPT и Gemini: кибератаки на память ИИ и создание ложных воспоминаний

21 июля 2026

Обзор курса «Английский с ИИ»: как персонализированное обучение с ИИ удваивает скорость изучения

21 июля 2026

Как AI-агент ASI Biont интегрируется с датчиками окружающей среды для IoT-автоматизации без кода

21 июля 2026

Креативность и инновации: как дизайн-мышление, SCAMPER и TRIZ меняют подход к генерации идей — курс Asibiont

21 июля 2026

Как Low-Code и No-Code платформы меняют бизнес: обзор Bubble, Airtable, Make и n8n на курсе Asibiont

21 июля 2026

Rust — системное программирование: как AI-обучение на Asibiont помогает освоить язык без GC и создать CLI-инструменты

21 июля 2026

Интеграция Google Ads с AI: Автоматизация рекламных кампаний без кода с ASI Biont

21 июля 2026