Вы открываете проект утром, копируете в нейронку задачу, получаете красивый компонент — и начинаете его переделывать. Меняете названия переменных, добавляете проверку данных с сервера, убираете стили, которые конфликтуют с общей темой. Знакомо?

Дело не в том, что нейросеть плохо пишет код. Дело в том, что она пишет код для другой задачи — для той, которую вы описали, а не для той, которая есть на самом деле.

Эта статья о том, как правильно описывать задачу, чтобы получить рабочий код с первого раза. Разберём три главных направления: компоненты, стили и тесты. А ещё поговорим о том, как давать нейросети контекст — описание данных с сервера и правила дизайн-системы.

Содержание

  1. Как просить компонент
  2. Стили без конфликтов
  3. Тесты, которые что-то проверяют
  4. Контекст: данные сервера и дизайн-система
  5. Приёмы, которые работают
  6. Частые ошибки и как их избежать
  7. Шаблоны запросов

Часть 1. Как просить компонент

Начнём с простого. Вот типичный запрос начинающего разработчика:

Напиши компонент карточки товара

Нейросеть напишет что-то. Скорее всего — рабочее. Но вы потратите час на доработку, потому что:

  • она не знает, какие данные приходят с сервера;
  • она не знает, как компонент встроен в страницу;
  • она придумает стили сама, и они не совпадут с вашими;
  • она сделает кнопки, которых в задаче нет, или не сделает те, что нужны.

Теперь посмотрим на хороший запрос:

Напиши компонент ProductCard на React с TypeScript.

Данные из API (тип уже объявлен в проекте):
interface Product {
  id: number;
  name: string;
  price: number;
  imageUrl: string;
  inStock: boolean;
}

Что должен делать компонент:
- показывать картинку, название и цену
- если inStock = false, показывать текст «Нет в наличии»
  и делать кнопку неактивной
- при клике на кнопку «Купить» вызывать onAddToCart(product.id)

Стили: использовать только классы из нашей дизайн-системы.
Список доступных классов: card, card__image, card__title,
card__price, btn, btn--primary, btn--disabled.

Не нужно: анимации, hover-эффекты, адаптивность.

Разница очевидна. Во втором запросе нейросеть получила всё необходимое и не придумывает ничего лишнего.

Из чего состоит хороший запрос на компонент

1. Технология и версия

Всегда указывайте стек. «React» — это может быть React 16 с классовыми компонентами или React 18 с хуками. Нейросеть угадает, но не всегда правильно.

// Плохо
Напиши компонент для формы входа

// Хорошо
Напиши функциональный компонент LoginForm на React 18
с TypeScript. Управление формой через react-hook-form.

2. Интерфейс данных

Если у вас уже есть тип — вставьте его целиком. Не пересказывайте словами, а скопируйте код. Нейросеть точно воспроизведёт имена полей и не перепутает price с cost.

3. Поведение, а не внешний вид

Описывайте, что происходит, а не как это выглядит. «Кнопка серая когда нет данных» — плохо. «Кнопка disabled и имеет класс btn--disabled, если массив items пуст» — хорошо.

4. Что не нужно делать

Это важный пункт, который часто пропускают. Нейросеть любит добавлять «полезные» вещи: уведомления, анимации, проверку на мобильных устройствах. Прямо скажите, что вам не нужно.

Не нужно:
- обработка ошибок сети (делается выше по дереву)
- анимации и переходы
- адаптивная вёрстка (сетка задаётся снаружи)

5. Место компонента в приложении

Скажите, откуда берутся данные и куда идут действия. Это помогает нейросети понять, нужен ли компоненту собственный запрос к серверу или он получает данные через свойства.

Компонент получает данные через props от родителя UserPage.
Сам запросы не делает.
При удалении вызывает onDelete(userId) — обработчик снаружи.

Пример полного запроса на компонент

Напиши компонент UserCard на React 18 с TypeScript.

Входные данные (props):
interface UserCardProps {
  user: {
    id: number;
    name: string;
    email: string;
    role: 'admin' | 'user' | 'guest';
    avatarUrl?: string;
  };
  onEdit: (id: number) => void;
  onDelete: (id: number) => void;
}

Поведение:
- Если avatarUrl не задан, показывать первую букву имени
- Кнопку «Удалить» показывать только если role !== 'admin'
- При клике «Редактировать» — вызвать onEdit(user.id)

Стили: классы из нашей дизайн-системы:
card, card--horizontal, avatar, avatar--text,
badge, badge--admin, badge--user, badge--guest,
btn, btn--sm, btn--danger, btn--secondary

Не нужно: hover-эффекты, анимации, всплывающие подсказки.

Храните шаблон такого запроса в заметках. Перед каждой новой задачей просто заполняйте его. Уже через неделю вы будете тратить на составление запроса 2 минуты вместо 15 — и получать код, который работает.

Часть 2. Стили без конфликтов

Главная проблема: нейросеть не видит ваши стили

Когда вы просите написать компонент, нейросеть создаёт стили заново. Она не знает, что у вас уже есть кнопки, отступы и цвета. В итоге появляются конфликты: ваш CSS и её CSS борются за одни и те же элементы.

Решение простое — нужно сообщить нейросети, что уже есть в проекте.

Три ситуации и как с ними работать

Ситуация 1. У вас есть дизайн-система с готовыми классами

Передайте список классов прямо в запрос. Попросите использовать только их.

Доступные классы из дизайн-системы:

Кнопки: btn, btn--primary, btn--secondary,
btn--danger, btn--sm, btn--lg, btn--disabled

Карточки: card, card__header, card__body, card__footer

Текст: text-sm, text-base, text-lg, text-bold,
text-muted, text-danger, text-success

Отступы: mt-1 (4px) до mt-8 (32px), аналогично mb, ml, mr, px, py

Использовать только эти классы. Собственный CSS не писать.

Если вы используете Tailwind, скажите об этом явно — и укажите, какие цвета и размеры определены в настройках вашего проекта.

Ситуация 2. Стили на уровне компонента (CSS-модули или styled-components)

Скажите, какой способ использовать, и покажите пример из вашего проекта. Нейросеть подстроится под ваш стиль именования.

Стили: CSS-модули. Пример того, как это делается в проекте:

// Button.module.css
.button { padding: 8px 16px; border-radius: 4px; }
.button--primary { background: #1976d2; color: white; }

// Button.tsx
import styles from './Button.module.css';
<button className={styles.button}>...</button>

Сделай то же самое для компонента Modal.

Ситуация 3. Нужно изменить существующий стиль

Вставьте текущий код стилей и скажите, что именно нужно поменять. Не просите «переписать» — просите «изменить конкретное место».

Вот текущий стиль карточки:

.card {
  background: white;
  border: 1px solid #e0e0e0;
  border-radius: 8px;
  padding: 16px;
}

Нужно:
- добавить тень: box-shadow: 0 2px 8px rgba(0,0,0,0.1)
- при наведении поднимать карточку: translateY(-2px)
- переход сделать 200мс ease

Остальное не трогать.

Как передать цвета и переменные

Если в проекте используются переменные CSS, передайте их список. Без этого нейросеть придумает свои цвета — похожие, но не ваши.

Переменные из нашего проекта:

--color-primary: #1976d2;
--color-primary-hover: #1565c0;
--color-danger: #d32f2f;
--color-text: #212121;
--color-text-secondary: #757575;
--color-border: #e0e0e0;
--color-bg: #f5f5f5;
--border-radius: 8px;
--shadow-sm: 0 1px 3px rgba(0,0,0,0.12);

Использовать только эти переменные. Не использовать
цвета напрямую (#fff, blue и т.д.).

Часть 3. Тесты, которые что-то проверяют

Почему тесты часто бесполезны

Нейросеть умеет писать тесты. Но если не направить её, вы получите тесты «для галочки» — они запускаются, проходят, но ничего не ловят. Типичный пример:

it('renders correctly', () => {
  const { container } = render(<UserCard user={mockUser} />);
  expect(container).toBeTruthy();
});

// Этот тест всегда будет проходить, пока компонент
// не выбрасывает ошибку при рендере. Он не проверяет ничего.

Хороший тест проверяет конкретное поведение. Чтобы его получить, нужно описать это поведение в запросе.

Как правильно просить тесты

Шаг 1. Опишите, что именно нужно проверить

Не «напиши тесты для компонента», а «напиши тесты для конкретных случаев»:

Напиши тесты для компонента ProductCard (React Testing Library).

Проверить:
1. Название и цена отображаются из props
2. Если inStock = false — кнопка disabled и есть текст «Нет в наличии»
3. Если inStock = true — кнопка активна
4. При клике на кнопку вызывается onAddToCart с правильным id
5. Если imageUrl не передан — изображение не рендерится

Шаг 2. Дайте данные для тестов

Если в компоненте есть сложный тип данных, передайте объект с данными. Нейросеть использует его в тестах, и вы сразу получите корректные значения полей.

Данные для тестов:

const mockProduct = {
  id: 42,
  name: 'Тестовый товар',
  price: 1500,
  imageUrl: 'https://example.com/img.jpg',
  inStock: true,
};

const outOfStockProduct = { ...mockProduct, inStock: false };

Шаг 3. Скажите, что нужно заменить заглушками

Если компонент использует маршрутизацию, контекст или запросы — скажите об этом. Нейросеть настроит нужные обёртки.

Замени заглушкой:
- useNavigate из react-router-dom (нам не нужна настоящая навигация)
- функцию onAddToCart (нам нужно проверить, что она вызвана,
  но не сама её логика)

Компонент нужно обернуть в MemoryRouter.

Пример полного запроса на тесты

Напиши тесты для UserCard (React Testing Library + Jest).

Компонент:
interface UserCardProps {
  user: { id: number; name: string; role: 'admin' | 'user' };
  onDelete: (id: number) => void;
}

Данные:
const adminUser = { id: 1, name: 'Иван', role: 'admin' };
const regularUser = { id: 2, name: 'Мария', role: 'user' };

Что проверить:
1. Имя пользователя отображается
2. Для admin — кнопки «Удалить» нет
3. Для user — кнопка «Удалить» есть
4. При клике «Удалить» вызывается onDelete(2)
5. Значок роли отображается правильно (Admin / User)

onDelete оборачивать в jest.fn().

Тесты для хуков

Если нужно протестировать собственный хук, скажите об этом явно и опишите, что хук принимает и возвращает.

Напиши тест для хука useCounter.

Хук:
function useCounter(initial: number) {
  // возвращает: count, increment, decrement, reset
}

Использовать renderHook из @testing-library/react.

Проверить:
1. Начальное значение равно переданному аргументу
2. increment увеличивает на 1
3. decrement уменьшает на 1
4. reset возвращает к начальному значению
5. count не может стать меньше 0

Часть 4. Контекст: данные сервера и дизайн-система

Почему контекст решает всё

Представьте, что вы просите коллегу написать компонент профиля, но не показываете ему макет и не говорите, какие данные приходят. Он сделает что-то — но вам придётся переделывать. С нейросетью то же самое.

Контекст — это информация, без которой нейросеть начинает придумывать. Два главных вида контекста для разработчика интерфейсов: описание данных от сервера и правила дизайн-системы.

Контекст 1. Данные от сервера

Передавайте реальные типы, а не пересказ

Если в проекте уже есть типы TypeScript — копируйте их. Не нужно переводить на слова: «сервер возвращает объект с полями имени и фамилии». Просто вставьте тип.

// Вот что приходит с сервера (из файла types/api.ts):

export interface OrderResponse {
  orderId: string;
  status: 'pending' | 'processing' | 'shipped' | 'delivered' | 'cancelled';
  createdAt: string; // ISO 8601
  items: OrderItem[];
  totalAmount: number; // в копейках
  shippingAddress: {
    city: string;
    street: string;
    building: string;
    apartment?: string;
  };
}

export interface OrderItem {
  productId: number;
  name: string;
  quantity: number;
  pricePerUnit: number; // в копейках
}

Обратите внимание на комментарий про копейки. Такие детали критически важны — без них нейросеть может отобразить цену неправильно.

Добавляйте примечания к нестандартным полям

Если поле устроено нестандартно — объясните это. Даты в виде строк, суммы в наименьших единицах, идентификаторы-строки вместо чисел — всё это источники ошибок.

Важные детали по данным:

- totalAmount и pricePerUnit — в копейках.
  Чтобы показать рубли: amount / 100
- createdAt — строка в формате ISO 8601.
  Для отображения: new Date(createdAt).toLocaleDateString('ru-RU')
- status отображается так:
    'pending'    → «Ожидает подтверждения»
    'processing' → «В работе»
    'shipped'    → «Отправлен»
    'delivered'  → «Доставлен»
    'cancelled'  → «Отменён»
- apartment — необязательное поле. Если не задано, не показывать.

Что делать, если типов нет

Если проект без TypeScript, покажите пример реального ответа сервера. Скопируйте из вкладки «Сеть» в инструментах разработчика и вставьте в запрос.

Вот пример ответа API (GET /api/orders/123):

{
  "orderId": "ORD-2024-001",
  "status": "shipped",
  "createdAt": "2024-03-15T10:30:00Z",
  "totalAmount": 259900,
  "items": [
    {
      "productId": 42,
      "name": "Кофемашина",
      "quantity": 1,
      "pricePerUnit": 259900
    }
  ]
}

Контекст 2. Дизайн-система

Три уровня — передавайте нужный

Уровень 1 — переменные и токены. Цвета, шрифты, отступы. Передайте список — нейросеть будет их использовать.

Уровень 2 — готовые классы. Список классов с описанием. Нейросеть применит нужные.

Уровень 3 — готовые компоненты. Если в проекте уже есть Button, Input, Modal — скажите об этом. Нейросеть не будет создавать их заново.

В проекте уже есть эти компоненты (из папки ui/):
- Button (props: variant, size, disabled, onClick, children)
- Input (props: value, onChange, placeholder, error)
- Modal (props: isOpen, onClose, title, children)
- Spinner (props: size)

Использовать их, не создавать свои.

Передача описания компонента из библиотеки

Если компонент из библиотеки имеет много настроек, передайте только то, что нужно для задачи. Не копируйте всю документацию — выберите нужные свойства.

Button из нашей библиотеки (нужные для задачи свойства):

variant: 'primary' | 'secondary' | 'ghost' | 'danger'
size: 'sm' | 'md' | 'lg'
disabled: boolean
loading: boolean  // показывает крутилку внутри кнопки
onClick: () => void

Пример:
<Button variant="primary" size="md" loading={isSubmitting}>
  Сохранить
</Button>

Часть 5. Приёмы, которые работают

Приём 1. Покажи существующий код

Один из самых эффективных способов передать контекст — показать, как что-то уже сделано в вашем проекте. Нейросеть подстроится под ваш стиль: именование переменных, структуру разметки, паттерны.

Вот как у нас реализован компонент UserCard:
[вставьте код компонента]

Сделай аналогичный компонент ProductCard с той же структурой,
но для товара (данные ниже).

Приём 2. Итерация вместо полного запроса

Не нужно описывать всё в одном запросе. Можно работать шагами: сначала получить скелет, потом добавить детали.

Шаг 1:
Сделай структуру компонента OrderList без стилей.
Данные: [вставьте тип]

Шаг 2 (после ответа):
Добавь стили используя классы: [список классов]

Шаг 3:
Добавь состояние загрузки и обработку пустого списка.

Этот подход помогает контролировать результат на каждом шаге и не тратить время на исправление большого куска кода.

Приём 3. Попроси объяснение

Если нейросеть сделала что-то неожиданно, попросите объяснить. Это помогает понять логику и решить, нужно ли менять подход.

Почему ты использовал useMemo здесь?
В каком случае это может вызвать проблемы?

Приём 4. Укажи на проблему точно

Если что-то не работает, не пишите «это не работает». Опишите конкретно: что происходит, что должно происходить, в каких условиях.

// Плохо
Кнопка не работает.

// Хорошо
Кнопка «Купить» остаётся активной, когда inStock = false.
Она должна быть disabled и иметь класс btn--disabled.
Вот текущий код кнопки: [вставьте код]

Приём 5. Попроси только нужное

Нейросеть может переписать весь файл, когда нужно изменить одну строку. Скажите, что хотите получить только изменённый фрагмент.

Нужно изменить только функцию formatPrice.
Покажи только изменённую функцию, не весь файл.

Часть 6. Частые ошибки и как их избежать

Ошибка 1. Расплывчатое описание задачи

Как бывает: «Сделай красивую форму для входа».

Проблема: «Красивую» — субъективно. Нейросеть придумает свою красоту.

Решение: Описывайте поведение, а не внешний вид. Стили передавайте через классы или переменные.

Ошибка 2. Запрос без данных

Как бывает: «Напиши компонент таблицы заказов».

Проблема: Нейросеть придумает поля таблицы — и они не совпадут с вашими данными.

Решение: Всегда передавайте тип данных или пример из API.

Ошибка 3. «Перепиши» вместо «измени»

Как бывает: «Перепиши этот компонент, чтобы он работал быстрее».

Проблема: Нейросеть переписывает всё целиком, меняя то, что трогать не нужно.

Решение: Сначала спросите: «Найди узкие места в этом коде и объясни, что можно улучшить». Потом просите конкретное изменение.

Ошибка 4. Длинная цепочка уточнений

Как бывает: Получили плохой результат — уточнили — получили другой плохой результат — уточнили снова.

Проблема: Нейросеть теряет контекст. Чем длиннее цепочка правок, тем больше она отклоняется.

Решение: Если после трёх итераций код всё ещё не то — начните заново с более полным запросом.

Ошибка 5. Слепое доверие к результату

Как бывает: Скопировали код, вставили, запустили — работает. Не читали.

Проблема: Нейросеть могла добавить логику, которая конфликтует с другой частью приложения, или использовать устаревший подход.

Решение: Читайте код перед вставкой. Хотя бы бегло. Обращайте внимание на то, чего не просили.

Часть 7. Шаблоны запросов

Скопируйте и заполняйте под свою задачу.

Шаблон: компонент

Напиши компонент [НАЗВАНИЕ] на [ТЕХНОЛОГИЯ + ВЕРСИЯ].

Данные (props / тип):
[вставьте интерфейс или тип]

Поведение:
- [условие 1 и что должно происходить]
- [условие 2 и что должно происходить]

Стили: [классы из дизайн-системы / CSS-переменные / CSS-модули]

Не нужно: [список того, что не делать]

Место в приложении: [откуда данные, куда идут события]

Шаблон: тесты

Напиши тесты для [НАЗВАНИЕ] (Jest + React Testing Library).

Данные для тестов:
[вставьте объекты с данными]

Проверить:
1. [конкретное поведение 1]
2. [конкретное поведение 2]
3. [граничный случай]

Заглушки:
- [что и как заменить]

Шаблон: изменение стилей

Измени стили для [КОМПОНЕНТ / ЭЛЕМЕНТ].

Текущий код:
[вставьте]

Что изменить:
- [конкретное изменение 1]
- [конкретное изменение 2]

Переменные: [список CSS-переменных]
Остальное не менять.

Три правила, которые стоит запомнить

  1. Передавайте данные, а не слова. Тип из TypeScript лучше любого описания на русском языке.
  2. Говорите, что не нужно делать. Это сокращает количество «полезных» дополнений, которые потом придётся убирать.
  3. Показывайте существующий код. Нейросеть подстроится под ваш стиль лучше, чем по любому текстовому описанию.

Начните с одного компонента. Составьте запрос по шаблону, сравните результат с тем, что получали раньше. Скорее всего, разница будет заметна сразу.


«Доктайп» — журнал о фронтенде. Читайте, слушайте и учитесь с нами.

ТелеграмПодкастБесплатные учебники