Промты для генерации JavaScript и TypeScript кода

{
"title": "15 промтов для генерации JavaScript и TypeScript кода: от React до Node.js",
"content": "## Введение\n\nПредставьте: вы пишете сложный компонент React с типизацией, а AI подсказывает не только реализацию, но и обрабатывает краевые случаи. Или генерирует middleware для Express с валидацией — за секунды. В 2026 году генерация кода через промты стала стандартом для продакшн-разработки. Согласно опросу Stack Overflow 2025, 72% разработчиков используют AI-ассистенты еженедельно, а для JavaScript/TypeScript этот показатель достигает 81%.\n\nВ этой подборке — 15 промтов, которые я собрал на основе реальных проектов и документации. Они покрывают React, Node.js, TypeScript и утилиты. Каждый промт содержит задачу, сам запрос, пример кода и пояснение. Вы сможете скопировать их и адаптировать под свои задачи.\n\n## Базовые промты (уровень: новичок)\n\n### 1. Генерация React-компонента с TypeScript\n\nЗадача: Создать компонент кнопки с вариантами (primary, secondary, danger) и обработчиком клика.\n\nПромт:\n```\nСгенерируй React-компонент Button на TypeScript. Компонент должен принимать props: variant ('primary'

| 'secondary' | 'danger'), onClick (функция), children (ReactNode). Реализуй стили через CSS-in-JS (styled-components или emotion). Учти disabled-состояние.\n\n\n**Пример результата:**\ntsx\nimport React from 'react';\nimport styled, { css } from 'styled-components';\n\ntype ButtonVariant = 'primary' | 'secondary' | 'danger';\n\ninterface ButtonProps {\n variant: ButtonVariant;\n onClick: () => void;\n children: React.ReactNode;\n disabled?: boolean;\n}\n\nconst variantStyles = {\n primary: cssbackground: #007bff; color: white;,\n secondary: cssbackground: #6c757d; color: white;,\n danger: cssbackground: #dc3545; color: white;,\n};\n\nconst StyledButton = styled.button<{ variant: ButtonVariant; disabled?: boolean }>\n padding: 10px 20px;\n border: none;\n border-radius: 4px;\n cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')};\n opacity: ${({ disabled }) => (disabled ? 0.6 : 1)};\n ${({ variant }) => variantStyles[variant]}\n;\n\nexport const Button: React.FC = ({ variant, onClick, children, disabled }) => {\n return (\n \n {children}\n \n );\n};\n\n\n**Пояснение:** Промт задаёт конкретные типы, дизайн-требования и состояния. Как отмечается в документации TypeScript, строгая типизация props предотвращает баги на этапе компиляции.\n\n### 2. Генерация Node.js middleware для Express\n\n**Задача:** Написать middleware для логирования запросов с метриками.\n\n**Промт:**\n\nСоздай middleware для Express.js на TypeScript, который логирует метод, URL, время выполнения запроса и статус ответа. Используй process.hrtime для точности. Выводи в формате JSON.\n\n\n**Пример результата:**\nts\nimport { Request, Response, NextFunction } from 'express';\n\nexport const requestLogger = (req: Request, res: Response, next: NextFunction): void => {\n const start = process.hrtime();\n res.on('finish', () => {\n const diff = process.hrtime(start);\n const duration = (diff[0] * 1e3 + diff[1] / 1e6).toFixed(2);\n console.log(JSON.stringify({\n method: req.method,\n url: req.originalUrl,\n status: res.statusCode,\n durationMs: parseFloat(duration),\n timestamp: new Date().toISOString(),\n }));\n });\n next();\n};\n\n\n**Пояснение:** Использование `process.hrtime` вместо `Date.now()` даёт наносекундную точность — это важно для замера быстрых операций. Подход рекомендован в Node.js Performance Guide.\n\n### 3. Генерация утилиты для работы с массивами\n\n**Задача:** Написать функцию глубокого сравнения объектов.\n\n**Промт:**\n\nНапиши на TypeScript функцию deepEqual, которая сравнивает два значения любого типа (включая вложенные объекты и массивы) по значению. Используй рекурсию. Обработай null, undefined, Date, RegExp.\n\n\n**Пример результата:**\nts\nexport function deepEqual(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (a == null || b == null) return false;\n if (typeof a !== typeof b) return false;\n\n if (a instanceof Date && b instanceof Date) {\n return a.getTime() === b.getTime();\n }\n if (a instanceof RegExp && b instanceof RegExp) {\n return a.source === b.source && a.flags === b.flags;\n }\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false;\n return a.every((val, idx) => deepEqual(val, b[idx]));\n }\n if (typeof a === 'object' && typeof b === 'object' && a !== null && b !== null) {\n const keysA = Object.keys(a as Record);\n const keysB = Object.keys(b as Record);\n if (keysA.length !== keysB.length) return false;\n return keysA.every(key => deepEqual((a as Record)[key], (b as Record)[key]));\n }\n return false;\n}\n\n\n**Пояснение:** Функция покрывает распространённые краевые случаи. Она использует `getTime()` для Date, что надёжнее `toString()`. Эта утилита пригодится в тестах или Redux reducers.\n\n## Продвинутые промты (уровень: middle)\n\n### 4. Генерация кастомного React-хука\n\n**Задача:** Хук для работы с localStorage с сериализацией и подпиской на изменения.\n\n**Промт:**\n\nСоздай React-хук useLocalStorage на TypeScript. Он должен принимать ключ и начальное значение, возвращать [value, setValue]. Значение должно автоматически сериализоваться в JSON. Добавь обработку ошибок JSON.parse. Хук должен обновлять состояние при изменении localStorage в других вкладках (событие storage).\n\n\n**Пример результата:**\ntsx\nimport { useState, useEffect, useCallback } from 'react';\n\nexport function useLocalStorage(key: string, initialValue: T): [T, (value: T | ((prev: T) => T)) => void] {\n const [storedValue, setStoredValue] = useState(() => {\n try {\n const item = window.localStorage.getItem(key);\n return item ? (JSON.parse(item) as T) : initialValue;\n } catch (error) {\n console.error(Error reading localStorage key \"${key}\":, error);\n return initialValue;\n }\n });\n\n const setValue = useCallback((value: T | ((prev: T) => T)) => {\n try {\n const valueToStore = value instanceof Function ? value(storedValue) : value;\n setStoredValue(valueToStore);\n window.localStorage.setItem(key, JSON.stringify(valueToStore));\n } catch (error) {\n console.error(Error setting localStorage key \"${key}\":, error);\n }\n }, [key, storedValue]);\n\n useEffect(() => {\n const handleStorageChange = (e: StorageEvent) => {\n if (e.key === key) {\n try {\n setStoredValue(e.newValue ? (JSON.parse(e.newValue) as T) : initialValue);\n } catch {\n setStoredValue(initialValue);\n }\n }\n };\n window.addEventListener('storage', handleStorageChange);\n return () => window.removeEventListener('storage', handleStorageChange);\n }, [key, initialValue]);\n\n return [storedValue, setValue];\n}\n\n\n**Пояснение:** Хук использует событие `storage` — это стандартный механизм браузера для синхронизации вкладок. Согласно MDN, обработка ошибок `JSON.parse` обязательна, так как данные могут быть повреждены.\n\n### 5. Генерация API-клиента на основе OpenAPI\n\n**Задача:** Создать типобезопасный клиент для REST API.\n\n**Промт:**\n\nСгенерируй на TypeScript класс HttpClient с методами get, post, put, delete. Используй дженерики для типов запроса и ответа. Добавь перехватчики (interceptors) для добавления токена и обработки ошибок. Реализуй retry-логику с экспоненциальной задержкой.\n\n\n**Пример результата:**\nts\ntype Interceptor = (config: RequestInit) => RequestInit | Promise;\n\ninterface HttpClientConfig {\n baseUrl: string;\n interceptors?: Interceptor[];\n retryCount?: number;\n}\n\nexport class HttpClient {\n private baseUrl: string;\n private interceptors: Interceptor[];\n private retryCount: number;\n\n constructor(config: HttpClientConfig) {\n this.baseUrl = config.baseUrl;\n this.interceptors = config.interceptors || [];\n this.retryCount = config.retryCount || 3;\n }\n\n private async request(method: string, url: string, body?: unknown): Promise {\n let config: RequestInit = {\n method,\n headers: { 'Content-Type': 'application/json' },\n body: body ? JSON.stringify(body) : undefined,\n };\n\n for (const interceptor of this.interceptors) {\n config = await interceptor(config);\n }\n\n let lastError: Error | null = null;\n for (let attempt = 0; attempt < this.retryCount; attempt++) {\n try {\n const response = await fetch(${this.baseUrl}${url}, config);\n if (!response.ok) {\n throw new Error(HTTP ${response.status}: ${response.statusText});\n }\n return (await response.json()) as T;\n } catch (error) {\n lastError = error as Error;\n if (attempt < this.retryCount - 1) {\n await new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt) * 1000));\n }\n }\n }\n throw lastError;\n }\n\n async get(url: string): Promise {\n return this.request('GET', url);\n }\n\n async post(url: string, body: U): Promise {\n return this.request('POST', url, body);\n }\n\n async put(url: string, body: U): Promise {\n return this.request('PUT', url, body);\n }\n\n async delete(url: string): Promise {\n return this.request('DELETE', url);\n }\n}\n\n\n**Пояснение:** Retry с экспоненциальной задержкой снижает нагрузку при временных ошибках (например, 503). Этот паттерн описан в книге «Designing Data-Intensive Applications».\n\n### 6. Генерация редьюсера Redux Toolkit\n\n**Задача:** Создать слайс для управления списком задач с асинхронными операциями.\n\n**Промт:**\n\nСоздай Redux Toolkit slice для Todo-приложения. Включи состояния: items (массив), loading, error. Реализуй асинхронные thunk'и: fetchTodos, addTodo, deleteTodo. Используй createAsyncThunk и createSlice.\n\n\n**Пример результата:**\nts\nimport { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit';\n\ninterface Todo {\n id: string;\n title: string;\n completed: boolean;\n}\n\ninterface TodosState {\n items: Todo[];\n loading: boolean;\n error: string | null;\n}\n\nconst initialState: TodosState = {\n items: [],\n loading: false,\n error: null,\n};\n\nexport const fetchTodos = createAsyncThunk('todos/fetchTodos', async () => {\n const response = await fetch('/api/todos');\n if (!response.ok) throw new Error('Failed to fetch todos');\n return (await response.json()) as Todo[];\n});\n\nexport const addTodo = createAsyncThunk('todos/addTodo', async (title: string) => {\n const response = await fetch('/api/todos', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ title, completed: false }),\n });\n if (!response.ok) throw new Error('Failed to add todo');\n return (await response.json()) as Todo;\n});\n\nexport const deleteTodo = createAsyncThunk('todos/deleteTodo', async (id: string) => {\n await fetch(/api/todos/${id}, { method: 'DELETE' });\n return id;\n});\n\nconst todosSlice = createSlice({\n name: 'todos',\n initialState,\n reducers: {},\n extraReducers: (builder) => {\n builder\n .addCase(fetchTodos.pending, (state) => {\n state.loading = true;\n state.error = null;\n })\n .addCase(fetchTodos.fulfilled, (state, action: PayloadAction) => {\n state.loading = false;\n state.items = action.payload;\n })\n .addCase(fetchTodos.rejected, (state, action) => {\n state.loading = false;\n state.error = action.error.message || 'Unknown error';\n })\n .addCase(addTodo.fulfilled, (state, action: PayloadAction) => {\n state.items.push(action.payload);\n })\n .addCase(deleteTodo.fulfilled, (state, action: PayloadAction) => {\n state.items = state.items.filter(todo => todo.id !== action.payload);\n });\n },\n});\n\nexport default todosSlice.reducer;\n\n\n**Пояснение:** `createAsyncThunk` автоматически генерирует action creators для pending, fulfilled и rejected. Это снижает шаблонный код. Рекомендация из официальной документации Redux Toolkit.\n\n## Экспертные промты (уровень: senior)\n\n### 7. Генерация декоратора для валидации аргументов\n\n**Задача:** Написать TypeScript-декоратор, проверяющий типы аргументов в runtime.\n\n**Промт:**\n\nСоздай декоратор метода @Validate, который принимает массив типов (string, number, boolean) и проверяет аргументы метода в runtime. Если тип не совпадает — бросает TypeError с именем аргумента.\n\n\n**Пример результата:**\nts\nfunction Validate(...types: ('string' | 'number' | 'boolean')[]) {\n return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {\n const originalMethod = descriptor.value;\n descriptor.value = function (...args: any[]) {\n args.forEach((arg, index) => {\n const expectedType = types[index];\n if (expectedType && typeof arg !== expectedType) {\n throw new TypeError(Argument ${index} at ${propertyKey} expected ${expectedType}, got ${typeof arg});\n }\n });\n return originalMethod.apply(this, args);\n };\n return descriptor;\n };\n}\n\nclass Calculator {\n @Validate('number', 'number')\n add(a: number, b: number): number {\n return a + b;\n }\n}\n\nconst calc = new Calculator();\ncalc.add(1, 2); // OK\ncalc.add(1, '2' as any); // TypeError: Argument 1 at add expected number, got string\n\n\n**Пояснение:** Декораторы в TypeScript — экспериментальная функция, но они широко используются в фреймворках (Angular, NestJS). Этот пример демонстрирует runtime-безопасность, что важно при интеграции с нетипизированными данными.\n\n### 8. Генерация WebSocket-сервера с авторизацией\n\n**Задача:** Создать WebSocket-сервер на Node.js с JWT-токенами.\n\n**Промт:**\n\nНапиши WebSocket-сервер на Node.js с использованием библиотеки ws и TypeScript. Реализуй авторизацию при подключении через JWT (проверка токена из query-параметра). Обработай события: connection, message, close. Добавь heartbeat для поддержания соединения.\n\n\n**Пример результата:**\nts\nimport { WebSocketServer, WebSocket } from 'ws';\nimport jwt from 'jsonwebtoken';\n\nconst JWT_SECRET = 'your-secret';\nconst PORT = 8080;\n\ninterface AuthenticatedSocket extends WebSocket {\n userId?: string;\n isAlive?: boolean;\n}\n\nconst wss = new WebSocketServer({ port: PORT });\n\nwss.on('connection', (ws: AuthenticatedSocket, req) => {\n const token = new URL(req.url || '', 'http://localhost').searchParams.get('token');\n if (!token) {\n ws.close(4001, 'Token required');\n return;\n }\n\n try {\n const decoded = jwt.verify(token, JWT_SECRET) as { userId: string };\n ws.userId = decoded.userId;\n ws.isAlive = true;\n\n ws.on('pong', () => {\n ws.isAlive = true;\n });\n\n ws.on('message', (data) => {\n console.log(Received from ${ws.userId}: ${data});\n wss.clients.forEach((client) => {\n if (client !== ws && (client as AuthenticatedSocket).userId) {\n client.send(data);\n }\n });\n });\n\n ws.on('close', () => {\n console.log(User ${ws.userId} disconnected);\n });\n\n ws.send(JSON.stringify({ type: 'connected', userId: ws.userId }));\n } catch (err) {\n ws.close(4001, 'Invalid token');\n }\n});\n\n// Heartbeat\nconst interval = setInterval(() => {\n wss.clients.forEach((ws) => {\n const authWs = ws as AuthenticatedSocket;\n if (authWs.isAlive === false) {\n return authWs.terminate();\n }\n authWs.isAlive = false;\n authWs.ping();\n });\n}, 30000);\n\nwss.on('close', () => clearInterval(interval));\n\nconsole.log(WebSocket server running on ws://localhost:${PORT});\n\n\n**Пояснение:** Heartbeat предотвращает накопление «мёртвых» соединений. JWT-авторизация на уровне WebSocket — стандарт для real-time приложений (чат, уведомления).\n\n### 9. Генерация пайпа для трансформации данных\n\n**Задача:** Создать типобезопасный пайп (pipe) для последовательной обработки данных.\n\n**Промт:**\n\nНапиши на TypeScript функцию pipe, которая принимает начальное значение и список функций-трансформеров. Каждая функция принимает результат предыдущей. Используй дженерики для вывода типов на каждом шаге. Пример: pipe(5, x => x * 2, x => x.toString()) // '10'.\n\n\n**Пример результата:**\nts\ntype AnyFunc = (...args: any[]) => any;\n\nexport function pipe(initial: T): T;\nexport function pipe(initial: T, fn1: (x: T) => A): A;\nexport function pipe(initial: T, fn1: (x: T) => A, fn2: (x: A) => B): B;\nexport function pipe(initial: T, fn1: (x: T) => A, fn2: (x: A) => B, fn3: (x: B) => C): C;\nexport function pipe(initial: unknown, ...fns: AnyFunc[]): unknown {\n return fns.reduce((acc, fn) => fn(acc), initial);\n}\n\n// Пример использования\nconst result = pipe(5, x => x * 2, x => x.toString());\nconsole.log(result); // '10' (тип string)\n\n\n**Пояснение:** Перегрузки функций (overloads) позволяют TypeScript выводить точные типы на каждом этапе. Этот паттерн часто используется в функциональном программировании (Ramda, lodash/fp).\n\n### 10. Генерация тестов с Jest и React Testing Library\n\n**Задача:** Написать тесты для компонента TodoList.\n\n**Промт:**\n\nСгенерируй тесты на Jest и React Testing Library для компонента TodoList. Компонент принимает items (массив объектов {id, title, completed}) и onToggle (функция). Тесты: рендер списка, вызов onToggle при клике, отображение пустого состояния.\n\n\n**Пример результата:**\ntsx\nimport React from 'react';\nimport { render, screen, fireEvent } from '@testing-library/react';\nimport { TodoList } from './TodoList';\n\ndescribe('TodoList', () => {\n const mockToggle = jest.fn();\n const items = [\n { id: '1', title: 'Learn React', completed: false },\n { id: '2', title: 'Write tests', completed: true },\n ];\n\n test('renders todo items', () => {\n render();\n expect(screen.getByText('Learn React')).toBeInTheDocument();\n expect(screen.getByText('Write tests')).toBeInTheDocument();\n });\n\n test('calls onToggle when clicking a todo', () => {\n render();\n fireEvent.click(screen.getByText('Learn React'));\n expect(mockToggle).toHaveBeenCalledWith('1');\n });\n\n test('shows empty state when no items', () => {\n render();\n expect(screen.getByText('No todos yet')).toBeInTheDocument();\n });\n});\n\n\n**Пояснение:** React Testing Library фокусируется на поведении, а не на деталях реализации. Это соответствует принципам Kent C. Dodds.\n\n### 11. Генерация GraphQL-резолвера с Dataloader\n\n**Задача:** Оптимизировать N+1 запросы в GraphQL.\n\n**Промт:**\n\nСоздай GraphQL-резолвер для пользователей с Dataloader на TypeScript. Используй библиотеку dataloader. Реализуй метод batchUsers, который принимает массив id и возвращает пользователей. Подключи к Apollo Server.\n\n\n**Пример результата:**\nts\nimport DataLoader from 'dataloader';\n\ninterface User {\n id: string;\n name: string;\n email: string;\n}\n\nasync function batchUsers(ids: readonly string[]): Promise {\n const users = await db.users.find({ id: { $in: ids } }).toArray();\n const userMap = new Map(users.map(user => [user.id, user]));\n return ids.map(id => userMap.get(id)!);\n}\n\nconst userLoader = new DataLoader(batchUsers);\n\nconst resolvers = {\n Query: {\n users: async () => {\n return await db.users.find().toArray();\n },\n },\n User: {\n posts: async (parent: User) => {\n return await postLoader.load(parent.id);\n },\n },\n};\n\n\n**Пояснение:** Dataloader группирует запросы и кэширует результаты. Это решает проблему N+1, описанную в документации Apollo.\n\n### 12. Генерация обработчика ошибок для Express\n\n**Задача:** Централизованный обработчик ошибок с кастомными классами.\n\n**Промт:**\n\nСоздай на TypeScript централизованный обработчик ошибок для Express. Определи кастомные классы ошибок: NotFoundError, ValidationError, UnauthorizedError. Реализуй middleware, который ловит ошибки и возвращает JSON с кодом и сообщением.\n\n\n**Пример результата:**\nts\nimport { Request, Response, NextFunction } from 'express';\n\nexport class AppError extends Error {\n constructor(public statusCode: number, message: string) {\n super(message);\n this.name = this.constructor.name;\n }\n}\n\nexport class NotFoundError extends AppError {\n constructor(message = 'Resource not found') {\n super(404, message);\n }\n}\n\nexport class ValidationError extends AppError {\n constructor(message = 'Validation failed') {\n super(400, message);\n }\n}\n\nexport class UnauthorizedError extends AppError {\n constructor(message = 'Unauthorized') {\n super(401, message);\n }\n}\n\nexport const errorHandler = (err: Error, req: Request, res: Response, next: NextFunction) => {\n if (err instanceof AppError) {\n return res.status(err.statusCode).json({\n status: 'error',\n message: err.message,\n });\n }\n\n console.error('Unhandled error:', err);\n return res.status(500).json({\n status: 'error',\n message: 'Internal server error',\n });\n};\n\n\n**Пояснение:** Кастомные классы ошибок делают код самодокументируемым. Этот паттерн рекомендован в документации Express для продакшн-приложений.\n\n### 13. Генерация конфигурации Webpack с оптимизациями\n\n**Задача:** Создать оптимизированную конфигурацию Webpack для React.\n\n**Промт:**\n\nСгенерируй конфигурацию Webpack 5 для React-приложения на TypeScript. Включи: code splitting (React.lazy), минификацию TerserPlugin, хэши в именах файлов, разделение vendor-чанков, source maps для development.\n\n\n**Пример результата:**\njs\nconst path = require('path');\nconst HtmlWebpackPlugin = require('html-webpack-plugin');\nconst TerserPlugin = require('terser-webpack-plugin');\n\nmodule.exports = (env, argv) => {\n const isDev = argv.mode === 'development';\n\n return {\n entry: './src/index.tsx',\n output: {\n path: path.resolve(__dirname, 'dist'),\n filename: isDev ? '[name].js' : '[name].[contenthash].js',\n chunkFilename: isDev ? '[name].js' : '[name].[contenthash].chunk.js',\n clean: true,\n },\n resolve: {\n extensions: ['.tsx', '.ts', '.js', '.jsx'],\n },\n module: {\n rules: [\n {\n test: /\.tsx?$/,\n use: 'ts-loader',\n exclude: /node_modules/,\n },\n ],\n },\n plugins: [\n new HtmlWebpackPlugin({\n template: './public/index.html',\n }),\n ],\n optimization: {\n minimizer: [new TerserPlugin()],\n splitChunks: {\n chunks: 'all',\n cacheGroups: {\n vendor: {\n test: /[\\/]node_modules[\\/]/,\n name: 'vendors',\n chunks: 'all',\n },\n },\n },\n },\n devtool: isDev ? 'eval-source-map' : 'source-map',\n devServer: {\n port: 3000,\n hot: true,\n historyApiFallback: true,\n },\n };\n};\n\n\n**Пояснение:** Content hash в именах файлов гарантирует инвалидацию кэша при изменении кода. Разделение vendor-чанков уменьшает размер бандла.\n\n### 14. Генерация скрипта миграции данных\n\n**Задача:** Написать скрипт для миграции из MongoDB в PostgreSQL.\n\n**Промт:**\n\nСоздай на TypeScript скрипт для миграции пользователей из MongoDB (коллекция users) в PostgreSQL (таблица users). Используй библиотеки mongodb и pg. Реализуй пакетную вставку по 100 записей. Обработай дубликаты (upsert).\n\n\n**Пример результата:**\nts\nimport { MongoClient } from 'mongodb';\nimport { Pool } from 'pg';\n\nconst MONGO_URI = 'mongodb://localhost:27017/mydb';\nconst PG_CONNECTION = 'postgresql://user:pass@localhost:5432/mydb';\nconst BATCH_SIZE = 100;\n\nasync function migrate() {\n const mongoClient = new MongoClient(MONGO_URI);\n const pgPool = new Pool({ connectionString: PG_CONNECTION });\n\n try {\n await mongoClient.connect();\n const db = mongoClient.db();\n const users = db.collection('users');\n const cursor = users.find();\n\n let batch: any[] = [];\n for await (const doc of cursor) {\n batch.push({\n id: doc._id.toString(),\n name: doc.name,\n email: doc.email,\n created_at: doc.createdAt || new Date(),\n });\n\n if (batch.length >= BATCH_SIZE) {\n await insertBatch(pgPool, batch);\n batch = [];\n }\n }\n if (batch.length > 0) {\n await insertBatch(pgPool, batch);\n }\n\n console.log('Migration completed');\n } finally {\n await mongoClient.close();\n await pgPool.end();\n }\n}\n\nasync function insertBatch(pool: Pool, rows: any[]) {\n const values = rows.map((r, i) => ($${i * 3 + 1}, $${i * 3 + 2}, $${i * 3 + 3}, $${i * 3 + 4})).join(', ');\n const params = rows.flatMap(r => [r.id, r.name, r.email, r.created_at]);\n\n await pool.query(\n INSERT INTO users (id, name, email, created_at)\n VALUES ${values}\n ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name, email = EXCLUDED.email\n, params);\n}\n\nmigrate().catch(console.error);\n\n\n**Пояснение:** Пакетная вставка с upsert минимизирует время выполнения и обрабатывает дубликаты. Это критично для миграции больших объёмов данных.\n\n### 15. Генерация асинхронной очереди задач\n\n**Задача:** Реализовать очередь задач с приоритетами.\n\n**Промт:**\n\nНапиши на TypeScript класс AsyncQueue с методами enqueue (добавляет задачу с приоритетом) и dequeue (забирает задачу с наивысшим приоритетом). Используй бинарную кучу (binary heap) для эффективности. Обработай случай пустой очереди (возвращай Promise, который резолвится при добавлении).\n\n\n**Пример результата:**\nts\ntype Task = { priority: number;

← Все статьи

Комментарии

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