diff --git a/README.md b/README.md index 868033e..59fad15 100644 --- a/README.md +++ b/README.md @@ -31,9 +31,9 @@ - Конфигурация VitePress — `.vitepress/config.ts`. - `README.md` — описание проекта и не связан с `parts/`. -## Генерация .cursorrules +## Генерация RULES.md -- Файл `.cursorrules` собирается из содержимого `parts/`. +- Файл `RULES.md` собирается из содержимого `parts/`. - Команда: ```bash npm run docs diff --git a/RULES.md b/RULES.md new file mode 100644 index 0000000..b8efe1e --- /dev/null +++ b/RULES.md @@ -0,0 +1,630 @@ + + + +# Технологии и библиотеки + +Базовый стек технологий и библиотек, на который опираются проекты и примеры в документации. + +## Что используем обычно + +- **TypeScript** — типизация всей логики и компонентов. +- **FSD (Feature-Sliced Design)** — структура проекта и границы модулей. +- **React + Next.js** — основной стек для UI и приложения. +- **Mantine UI** — базовые UI-компоненты. +- **SWR** — получение данных по GET (кеширование и revalidate). +- **Zustand** — глобальное состояние. +- **i18next (i18n)** — локализация всех пользовательских текстов. +- **Vitest** — тестирование. +- **PostCSS Modules** — изоляция стилей. +- **Mobile First** — подход к адаптивной верстке. + + + + +# Архитектура + +Архитектура построена на FSD (Feature‑Sliced Design) и строгих границах модулей. +Цель — разделить ответственность, упростить сопровождение и контроль зависимостей. + +## Принципы + +- Разделять UI, бизнес-логику и инфраструктуру. +- Держать зависимости однонаправленными. +- Открывать наружу только публичный API модулей. +- Не допускать циклических зависимостей. + +## Слои + +- **app** — инициализация приложения, роутинг, конфигурации, глобальные провайдеры. +- **screens** — экраны и их композиция. +- **layouts** — каркас и шаблоны страниц. +- **widgets** — крупные блоки интерфейса, собирающие несколько сценариев. +- **features** — отдельные пользовательские действия и сценарии. +- **entities** — бизнес-сущности и их модель. +- **shared** — переиспользуемая инфраструктура, утилиты и базовые UI‑компоненты. + +## Правила зависимостей + +- Допустимые импорты идут сверху вниз: `app → screens → layouts → widgets → features → entities → shared`. +- Импорты между слоями — через публичный API. +- Внутри одного слоя — относительные импорты. + +## Публичный API модулей + +- Каждый модуль экспортирует наружу только то, что нужно другим слоям. +- Внешние импорты идут только через `index`‑файл модуля. +- Внутренние файлы не импортируются напрямую извне. + +## Границы ответственности + +- Бизнес‑логика не размещается в UI‑компонентах. +- UI‑компоненты должны быть максимально простыми и предсказуемыми. +- Связь между независимыми сценариями поднимается на уровень выше. + +## Типовые ошибки + +- Импорт из более высокого слоя в более низкий. +- Смешивание логики нескольких слоёв в одном модуле. +- Прямые импорты внутренних файлов, минуя публичный API. + + + + +# Стиль кода + +Раздел описывает единые правила оформления кода: отступы, переносы, кавычки, порядок импортов и базовую читаемость. + +## Отступы + +- 2 пробела (не табы). + +## Длина строк + +- Ориентироваться на 100 символов, но превышение допустимо, если строка читается легко. +- Переносить выражение на новые строки, когда строка становится плохо читаемой. +- Не переносить строку внутри строковых литералов без необходимости. + +**Хорошо** +```ts +const config = createRequestConfig( + endpoint, + { + headers: { + 'X-Request-Id': requestId, + 'X-User-Id': userId, + }, + params: { + page, + pageSize, + sort: 'createdAt', + }, + }, + timeoutMs, +); +``` + +**Плохо** +```ts +// Плохо: длинная строка с вложенными структурами плохо читается. +const config = createRequestConfig(endpoint, { headers: { 'X-Request-Id': requestId, 'X-User-Id': userId }, params: { page, pageSize, sort: 'createdAt' } }, timeoutMs); +``` + +## Кавычки + +- В JavaScript/TypeScript использовать одинарные кавычки. +- В JSX/TSX для атрибутов использовать двойные кавычки. +- Шаблонные строки использовать только при интерполяции или многострочном тексте. + +**Хорошо** +```ts +const label = 'Сохранить'; +const title = `Привет, ${name}`; +``` + +```tsx + +``` + +**Плохо** +```ts +// Плохо: двойные кавычки в TS и конкатенация вместо шаблонной строки. +const label = "Сохранить"; +const title = 'Привет, ' + name; +``` + +```tsx +// Плохо: одинарные кавычки в JSX-атрибутах. + +``` + +## Точки с запятой и запятые + +- Допускаются упущения точки с запятой, если код остаётся читаемым и однозначным. +- В многострочных массивах, объектах и параметрах функции запятая в конце допускается, но не обязательна. + +## Импорты + +- В именованных импортах использовать пробелы внутри фигурных скобок. +- Типы импортировать через `import type`. +- `default` импорт и экспорт избегать, использовать именованные. +- Избегать импорта всего модуля через `*`. + +**Хорошо** +```ts +import { MyComponent } from 'MyComponent'; +import type { User } from '../model/types'; +``` + +**Плохо** +```ts +// Плохо: default импорт и отсутствие пробелов в именованном импорте. +import MyComponent from 'MyComponent'; +import type {User} from '../model/types'; +``` + +## Ранние возвраты (early return) + +- Использовать ранние возвраты для упрощения чтения. +- Избегать `else` после `return`. + +**Хорошо** +```ts +const getName = (user?: { name: string }) => { + if (!user) { + return 'Гость'; + } + + return user.name; +}; +``` + +**Плохо** +```ts +// Плохо: лишний else после return усложняет чтение. +const getName = (user?: { name: string }) => { + if (user) { + return user.name; + } else { + return 'Гость'; + } +}; +``` + +## Форматирование объектов и массивов + +- В многострочных объектах каждое свойство на новой строке. +- В многострочных массивах каждый элемент на новой строке. +- Объекты и массивы можно писать в одну строку, если длина строки не превышает 100 символов. +- В однострочных объектах и массивах использовать пробелы после запятых. + +**Хорошо** +```ts +const roles = ['admin', 'editor', 'viewer']; +const options = { id: 1, name: 'User' }; + +const config = { + url: '/api/users', + method: 'GET', + params: { page: 1, pageSize: 20 }, +}; +``` + +**Плохо** +```ts +// Плохо: нет пробелов после запятых и объект слишком длинный для одной строки. +const roles = ['admin','editor','viewer']; +const options = { id: 1,name: 'User' }; +const config = { url: '/api/users', method: 'GET', params: { page: 1, pageSize: 20 } }; +``` + + + + +# Именование + +Именование должно быть предсказуемым, коротким и отражать смысл сущности. + +## Базовые правила + +| Что | Рекомендуется | +| ---------------- | ---------------------- | +| Папки | `kebab-case` | +| Файлы | `kebab-case` | +| Переменные | `camelCase` | +| Константы | `SCREAMING_SNAKE_CASE` | +| Классы | `PascalCase` | +| React-компоненты | `PascalCase` | +| Хуки | `useSomething` | +| CSS классы | `camelCase` | + + +## Архитектурный неймспейс + +Соглашение о суффиксах, которые обозначают слой (уровень абстракции), роль или тип файла. + +- Суффиксы используются для обозначения слоя, роли или типа файла. +- Суффиксы всегда пишутся в единственном числе. +- Формат имени: `name..ts` или `name..tsx`. + +**UI и слои FSD** +- `.screen.tsx` — экран +- `.layout.tsx` — layout +- `.widget.tsx` — виджет +- `.feature.tsx` — UI фичи +- `.entity.tsx` — UI сущности +- `.ui.tsx` — UI‑компонент + +**Логика и модель** +- `.store.ts` — стор +- `.service.ts` — сервис + +**Типы и контракты** +- `.type.ts` — типы и интерфейсы +- `.interface.ts` — файл с интерфейсами (если нужен отдельный контракт) +- `.enum.ts` — enum +- `.dto.ts` — внешние DTO +- `.schema.ts` — схемы валидации +- `.constant.ts` — константы +- `.config.ts` — конфигурация + +**Утилиты и хелперы** +- `.util.ts` — утилиты +- `.helper.ts` — вспомогательные функции +- `.lib.ts` — вспомогательные функции + +**Тесты** +- `.test.ts` / `.test.tsx` +- `.mock.ts` + + +**Хорошо** +```text +src/ +├── screens/ +│ └── main/ +│ ├── main.screen.tsx +│ └── index.ts +├── features/ +│ └── auth-by-email/ +│ ├── ui/ +│ │ └── login-form.ui.tsx +│ ├── auth-by-email.feature.tsx +│ └── index.ts +└── shared/ + └── ui/ + └── icon/ + ├── icon.ui.tsx + └── icon.module.css +``` + +**Плохо** +```text +// Плохо: нет единых правил для слоёв и публичных файлов. +src/ +├── screens/ +│ └── Main/ +│ └── Main.tsx +└── features/ + └── authByEmail/ + └── login-form.tsx +``` + +## Булевы значения + +- Использовать префиксы `is`, `has`, `can`, `should`. + +**Хорошо** +```ts +const isReady = true; +const hasAccess = false; +const canSubmit = true; +const shouldRedirect = false; +``` + +**Плохо** +```ts +// Плохо: неясное булево значение без префикса. +const ready = true; +const access = false; +const submit = true; +``` + +## События и обработчики + +- Обработчики начинать с `handle`. +- События и колбэки начинать с `on`. + +**Хорошо** +```ts +const handleSubmit = () => { ... }; +const onSubmit = () => { ... }; +``` + +**Плохо** +```ts +// Плохо: неочевидное назначение имени. +const submitClick = () => { ... }; +``` + +## Коллекции + +- Для массивов использовать имена во множественном числе. +- Для словарей/мап — использовать суффиксы `ById`, `Map`, `Dict`. + +**Хорошо** +```ts +const users = []; +const usersById = {} as Record; +const userIds = ['u1', 'u2']; +const ordersMap = new Map(); +const featureFlagsDict = { beta: true, legacy: false } as Record; +``` + +**Плохо** +```ts +// Плохо: имя не отражает, что это коллекция. +const user = []; +// Плохо: словарь назван как массив. +const usersMap = []; +// Плохо: по имени непонятно, что это словарь. +const users = {} as Record; +``` + + + + +# Документирование + +Документирование должно помогать понять назначение сущности, а не дублировать её типы или очевидные детали. + +## Правила + +- Документировать только назначение функций, компонентов, типов, интерфейсов и enum. +- Не документировать параметры, возвращаемые значения, типы пропсов и очевидные детали. +- В интерфейсах, типах и enum описывать только смысл поля или значения. +- Описание должно быть кратким, информативным и завершаться точкой. + +## Примеры + +**Хорошо** +```ts +/** + * Список задач пользователя. + */ +export const TodoList = memo(() => { ... }); + +/** + * Интерфейс задачи. + */ +export interface TodoItem { + /** Уникальный идентификатор задачи. */ + id: string; + /** Текст задачи. */ + text: string; + /** Статус выполнения задачи. */ + completed: boolean; +} + +/** + * Перечисление фильтров задач. + */ +export enum TodoFilter { + /** Все задачи. */ + All = 'all', + /** Только активные задачи. */ + Active = 'active', + /** Только выполненные задачи. */ + Completed = 'completed', +} +``` + +**Плохо** +```ts +// Плохо: дублирование параметров и возвращаемых значений. +/** + * @param id - идентификатор задачи + * @returns объект задачи + */ + +// Плохо: описание очевидных деталей. +/** + * id — идентификатор задачи + * text — текст задачи + * completed — статус выполнения + */ +``` + + + + +# Типизация + +Типизация обязательна для всех публичных интерфейсов, функций и компонентов. +Цель — предсказуемость, безопасность и автодополнение. + +## Общие правила + +- Указывать типы для параметров компонентов, возвращаемых значений и параметров функций. +- Предпочитать `type` для описания сущностей и `interface` для расширяемых контрактов. +- Избегать `any` и `unknown` без необходимости. +- Не использовать `ts-ignore`, кроме крайних случаев с явным комментарием причины. + +## Типы для компонентов + +- Типизировать параметры и публичный интерфейс компонента. +- Дефолтные значения описывать явно в коде. + +**Хорошо** +```tsx +/** + * Параметры кнопки. + */ +interface IOwnProps extends HTMLAttributes { + /** Текст кнопки. */ + label: string; + /** Обработчик клика по кнопке. */ + onClick: () => void; +} + +/** + * Кнопка с пользовательскими стилями. + */ +export const Button:FC = ({ className, label, onClick, ...htmlAttr }) => { + return ( +
+ button +
+ ) +} +``` + +**Плохо** +```tsx +// Плохо: параметры не типизированы. +export const Button = (props) => ( + +); +``` + +## Функции + +- Для публичных функций указывать возвращаемый тип. +- Не полагаться на неявный вывод для важных API. + +**Хорошо** +```ts +export const formatPrice = (value: number): string => { + return `${value} ₽`; +}; +``` + +**Плохо** +```ts +// Плохо: нет явного возвращаемого типа. +export const formatPrice = (value: number) => { + return `${value} ₽`; +}; +``` + +## Работа с any/unknown + +- `any` использовать только для временных заглушек. +- `unknown` сужать через проверки перед использованием. + +**Хорошо** +```ts +const parse = (value: unknown): string => { + if (typeof value === 'string') { + return value; + } + + return ''; +}; +``` + +**Плохо** +```ts +// Плохо: any отключает проверку типов. +const parse = (value: any) => value; +``` + + + + +# Структура проекта + +Раздел описывает базовую структуру проекта и принципы организации модулей на уровне папок и файлов. + +## Базовая структура проекта + +**Хорошо** +```text +src/ +├── app/ # Инициализация приложения, роутинг, провайдеры +│ ├── config/ # Конфигурации и константы уровня приложения +│ ├── providers/ # Провайдеры и обёртки приложения +│ ├── routing/ # Конфигурация маршрутов +│ └── index.ts # Публичный API слоя +├── screens/ # Экраны приложения +│ └── Profile/ # Экран профиля +│ └── ... # ui/model/index.ts +├── layouts/ # Общие шаблоны и каркасы страниц +│ └── MainLayout/ # Основной layout +│ └── ... # ui/index.ts +├── widgets/ # Крупные блоки интерфейса +│ └── Header/ # Виджет шапки +│ └── ... # ui/index.ts +├── features/ # Пользовательские сценарии +│ └── auth-by-email/ # Авторизация по email +│ └── ... # ui/model/api/index.ts +├── entities/ # Бизнес-сущности +│ └── user/ # Сущность пользователя +│ └── ... # ui/model/api/lib/index.ts +└── shared/ # Общие ресурсы проекта + ├── ui/ # Базовые UI-компоненты + ├── lib/ # Утилиты и хелперы + ├── services/ # Общие сервисы и клиенты + ├── config/ # Общие конфигурации + ├── styles/ # Глобальные стили и токены + └── assets/ # Ресурсы + ├── images/ # Изображения + ├── icons/ # Иконки + ├── fonts/ # Шрифты + └── video/ # Видео +``` + +**Плохо** +```text +// Плохо: слои смешаны, нет понятных границ и публичного API. +src/ +├── components/ +├── api/ +├── styles/ +└── user.ts +``` + +## Правила организации + +- Каждый слой и модуль хранится в собственной папке. +- Внутренние реализации разделяются на `ui`, `model`, `lib`, `api`. +- Публичный API модуля объявляется в `index.ts`. +- Внутренние файлы не импортируются напрямую извне. +- Не смешивать ответственность разных слоёв в одном модуле. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/concat-md.js b/concat-md.js index f42ef52..82f2ac3 100644 --- a/concat-md.js +++ b/concat-md.js @@ -16,8 +16,8 @@ const resultMd = concatMdSync("./parts", { } }); -// Записываем результат в файл .cursorrules в корне проекта -const outputPath = path.join("./", ".cursorrules"); +// Записываем результат в файл RULES.md в корне проекта +const outputPath = path.join("./", "RULES.md"); fs.writeFileSync(outputPath, resultMd, "utf8"); -console.log(`Файл .cursorrules успешно создан: ${outputPath}`); +console.log(`Файл RULES.md успешно создан: ${outputPath}`); diff --git a/index.md b/index.md index 722599b..e0e2343 100644 --- a/index.md +++ b/index.md @@ -4,7 +4,11 @@ ## Как пользоваться -- Начните со «Технологии и библиотеки», чтобы понимать базовые допущения. +- Начните с «Технологии и библиотеки», чтобы понимать базовые допущения. - Затем прочитайте разделы из «Базовых правил». - При реализации используйте соответствующие прикладные разделы. +## Для ассистентов + +Для передачи ассистенту используйте сконкатенированную версию документации: +https://gromlab.ru/docs/react-ts. diff --git a/parts/3-code-style.md b/parts/3-code-style.md index 72bf69b..9a286a3 100644 --- a/parts/3-code-style.md +++ b/parts/3-code-style.md @@ -6,29 +6,9 @@ title: Стиль кода Раздел описывает единые правила оформления кода: отступы, переносы, кавычки, порядок импортов и базовую читаемость. -## Отступы и переносы +## Отступы -- Использовать 2 пробела для отступов. -- Не использовать табы. -- Одна инструкция — одна строка. -- Между логическими блоками оставлять пустую строку по необходимости, если это улучшает читаемость. -- В многострочных конструкциях выравнивать закрывающую скобку по началу выражения. - -**Хорошо** -```ts -const payload = { - id: 1, - name: 'User', - meta: { - role: 'admin', - }, -}; -``` - -**Плохо** -```ts -const payload = { id: 1, name: 'User', meta: { role: 'admin' } }; -``` +- 2 пробела (не табы). ## Длина строк @@ -57,6 +37,7 @@ const config = createRequestConfig( **Плохо** ```ts +// Плохо: длинная строка с вложенными структурами плохо читается. const config = createRequestConfig(endpoint, { headers: { 'X-Request-Id': requestId, 'X-User-Id': userId }, params: { page, pageSize, sort: 'createdAt' } }, timeoutMs); ``` @@ -78,11 +59,13 @@ const title = `Привет, ${name}`; **Плохо** ```ts +// Плохо: двойные кавычки в TS и конкатенация вместо шаблонной строки. const label = "Сохранить"; const title = 'Привет, ' + name; ``` ```tsx +// Плохо: одинарные кавычки в JSX-атрибутах. ``` @@ -106,6 +89,7 @@ import type { User } from '../model/types'; **Плохо** ```ts +// Плохо: default импорт и отсутствие пробелов в именованном импорте. import MyComponent from 'MyComponent'; import type {User} from '../model/types'; ``` @@ -128,6 +112,7 @@ const getName = (user?: { name: string }) => { **Плохо** ```ts +// Плохо: лишний else после return усложняет чтение. const getName = (user?: { name: string }) => { if (user) { return user.name; @@ -146,7 +131,7 @@ const getName = (user?: { name: string }) => { **Хорошо** ```ts -const roles = ['admin', 'editor']; +const roles = ['admin', 'editor', 'viewer']; const options = { id: 1, name: 'User' }; const config = { @@ -158,7 +143,8 @@ const config = { **Плохо** ```ts -const roles = ['admin','editor']; +// Плохо: нет пробелов после запятых и объект слишком длинный для одной строки. +const roles = ['admin','editor','viewer']; const options = { id: 1,name: 'User' }; const config = { url: '/api/users', method: 'GET', params: { page: 1, pageSize: 20 } }; ``` diff --git a/parts/4-naming.md b/parts/4-naming.md index e69de29..509b3e1 100644 --- a/parts/4-naming.md +++ b/parts/4-naming.md @@ -0,0 +1,153 @@ +--- +title: Именование +--- + +# Именование + +Именование должно быть предсказуемым, коротким и отражать смысл сущности. + +## Базовые правила + +| Что | Рекомендуется | +| ---------------- | ---------------------- | +| Папки | `kebab-case` | +| Файлы | `kebab-case` | +| Переменные | `camelCase` | +| Константы | `SCREAMING_SNAKE_CASE` | +| Классы | `PascalCase` | +| React-компоненты | `PascalCase` | +| Хуки | `useSomething` | +| CSS классы | `camelCase` | + + +## Архитектурный неймспейс + +Соглашение о суффиксах, которые обозначают слой (уровень абстракции), роль или тип файла. + +- Суффиксы используются для обозначения слоя, роли или типа файла. +- Суффиксы всегда пишутся в единственном числе. +- Формат имени: `name..ts` или `name..tsx`. + +**UI и слои FSD** +- `.screen.tsx` — экран +- `.layout.tsx` — layout +- `.widget.tsx` — виджет +- `.feature.tsx` — UI фичи +- `.entity.tsx` — UI сущности +- `.ui.tsx` — UI‑компонент + +**Логика и модель** +- `.store.ts` — стор +- `.service.ts` — сервис + +**Типы и контракты** +- `.type.ts` — типы и интерфейсы +- `.interface.ts` — файл с интерфейсами (если нужен отдельный контракт) +- `.enum.ts` — enum +- `.dto.ts` — внешние DTO +- `.schema.ts` — схемы валидации +- `.constant.ts` — константы +- `.config.ts` — конфигурация + +**Утилиты и хелперы** +- `.util.ts` — утилиты +- `.helper.ts` — вспомогательные функции +- `.lib.ts` — вспомогательные функции + +**Тесты** +- `.test.ts` / `.test.tsx` +- `.mock.ts` + + +**Хорошо** +```text +src/ +├── screens/ +│ └── main/ +│ ├── main.screen.tsx +│ └── index.ts +├── features/ +│ └── auth-by-email/ +│ ├── ui/ +│ │ └── login-form.ui.tsx +│ ├── auth-by-email.feature.tsx +│ └── index.ts +└── shared/ + └── ui/ + └── icon/ + ├── icon.ui.tsx + └── icon.module.css +``` + +**Плохо** +```text +// Плохо: нет единых правил для слоёв и публичных файлов. +src/ +├── screens/ +│ └── Main/ +│ └── Main.tsx +└── features/ + └── authByEmail/ + └── login-form.tsx +``` + +## Булевы значения + +- Использовать префиксы `is`, `has`, `can`, `should`. + +**Хорошо** +```ts +const isReady = true; +const hasAccess = false; +const canSubmit = true; +const shouldRedirect = false; +``` + +**Плохо** +```ts +// Плохо: неясное булево значение без префикса. +const ready = true; +const access = false; +const submit = true; +``` + +## События и обработчики + +- Обработчики начинать с `handle`. +- События и колбэки начинать с `on`. + +**Хорошо** +```ts +const handleSubmit = () => { ... }; +const onSubmit = () => { ... }; +``` + +**Плохо** +```ts +// Плохо: неочевидное назначение имени. +const submitClick = () => { ... }; +``` + +## Коллекции + +- Для массивов использовать имена во множественном числе. +- Для словарей/мап — использовать суффиксы `ById`, `Map`, `Dict`. + +**Хорошо** +```ts +const users = []; +const usersById = {} as Record; +const userIds = ['u1', 'u2']; +const ordersMap = new Map(); +const featureFlagsDict = { beta: true, legacy: false } as Record; +``` + +**Плохо** +```ts +// Плохо: имя не отражает, что это коллекция. +const user = []; +// Плохо: словарь назван как массив. +const usersMap = []; +// Плохо: по имени непонятно, что это словарь. +const users = {} as Record; +``` diff --git a/parts/5-documentation.md b/parts/5-documentation.md index e69de29..6ed3d00 100644 --- a/parts/5-documentation.md +++ b/parts/5-documentation.md @@ -0,0 +1,64 @@ +--- +title: Документирование +--- + +# Документирование + +Документирование должно помогать понять назначение сущности, а не дублировать её типы или очевидные детали. + +## Правила + +- Документировать только назначение функций, компонентов, типов, интерфейсов и enum. +- Не документировать параметры, возвращаемые значения, типы пропсов и очевидные детали. +- В интерфейсах, типах и enum описывать только смысл поля или значения. +- Описание должно быть кратким, информативным и завершаться точкой. + +## Примеры + +**Хорошо** +```ts +/** + * Список задач пользователя. + */ +export const TodoList = memo(() => { ... }); + +/** + * Интерфейс задачи. + */ +export interface TodoItem { + /** Уникальный идентификатор задачи. */ + id: string; + /** Текст задачи. */ + text: string; + /** Статус выполнения задачи. */ + completed: boolean; +} + +/** + * Перечисление фильтров задач. + */ +export enum TodoFilter { + /** Все задачи. */ + All = 'all', + /** Только активные задачи. */ + Active = 'active', + /** Только выполненные задачи. */ + Completed = 'completed', +} +``` + +**Плохо** +```ts +// Плохо: дублирование параметров и возвращаемых значений. +/** + * @param id - идентификатор задачи + * @returns объект задачи + */ + +// Плохо: описание очевидных деталей. +/** + * id — идентификатор задачи + * text — текст задачи + * completed — статус выполнения + */ +``` diff --git a/parts/6-typing.md b/parts/6-typing.md index e69de29..0dcadf8 100644 --- a/parts/6-typing.md +++ b/parts/6-typing.md @@ -0,0 +1,96 @@ +--- +title: Типизация +--- + +# Типизация + +Типизация обязательна для всех публичных интерфейсов, функций и компонентов. +Цель — предсказуемость, безопасность и автодополнение. + +## Общие правила + +- Указывать типы для параметров компонентов, возвращаемых значений и параметров функций. +- Предпочитать `type` для описания сущностей и `interface` для расширяемых контрактов. +- Избегать `any` и `unknown` без необходимости. +- Не использовать `ts-ignore`, кроме крайних случаев с явным комментарием причины. + +## Типы для компонентов + +- Типизировать параметры и публичный интерфейс компонента. +- Дефолтные значения описывать явно в коде. + +**Хорошо** +```tsx +/** + * Параметры кнопки. + */ +interface IOwnProps extends HTMLAttributes { + /** Текст кнопки. */ + label: string; + /** Обработчик клика по кнопке. */ + onClick: () => void; +} + +/** + * Кнопка с пользовательскими стилями. + */ +export const Button:FC = ({ className, label, onClick, ...htmlAttr }) => { + return ( +
+ button +
+ ) +} +``` + +**Плохо** +```tsx +// Плохо: параметры не типизированы. +export const Button = (props) => ( + +); +``` + +## Функции + +- Для публичных функций указывать возвращаемый тип. +- Не полагаться на неявный вывод для важных API. + +**Хорошо** +```ts +export const formatPrice = (value: number): string => { + return `${value} ₽`; +}; +``` + +**Плохо** +```ts +// Плохо: нет явного возвращаемого типа. +export const formatPrice = (value: number) => { + return `${value} ₽`; +}; +``` + +## Работа с any/unknown + +- `any` использовать только для временных заглушек. +- `unknown` сужать через проверки перед использованием. + +**Хорошо** +```ts +const parse = (value: unknown): string => { + if (typeof value === 'string') { + return value; + } + + return ''; +}; +``` + +**Плохо** +```ts +// Плохо: any отключает проверку типов. +const parse = (value: any) => value; +``` diff --git a/parts/7-project-structure.md b/parts/7-project-structure.md index e69de29..5b47db5 100644 --- a/parts/7-project-structure.md +++ b/parts/7-project-structure.md @@ -0,0 +1,63 @@ +--- +title: Структура проекта +--- + +# Структура проекта + +Раздел описывает базовую структуру проекта и принципы организации модулей на уровне папок и файлов. + +## Базовая структура проекта + +**Хорошо** +```text +src/ +├── app/ # Инициализация приложения, роутинг, провайдеры +│ ├── config/ # Конфигурации и константы уровня приложения +│ ├── providers/ # Провайдеры и обёртки приложения +│ ├── routing/ # Конфигурация маршрутов +│ └── index.ts # Публичный API слоя +├── screens/ # Экраны приложения +│ └── Profile/ # Экран профиля +│ └── ... # ui/model/index.ts +├── layouts/ # Общие шаблоны и каркасы страниц +│ └── MainLayout/ # Основной layout +│ └── ... # ui/index.ts +├── widgets/ # Крупные блоки интерфейса +│ └── Header/ # Виджет шапки +│ └── ... # ui/index.ts +├── features/ # Пользовательские сценарии +│ └── auth-by-email/ # Авторизация по email +│ └── ... # ui/model/api/index.ts +├── entities/ # Бизнес-сущности +│ └── user/ # Сущность пользователя +│ └── ... # ui/model/api/lib/index.ts +└── shared/ # Общие ресурсы проекта + ├── ui/ # Базовые UI-компоненты + ├── lib/ # Утилиты и хелперы + ├── services/ # Общие сервисы и клиенты + ├── config/ # Общие конфигурации + ├── styles/ # Глобальные стили и токены + └── assets/ # Ресурсы + ├── images/ # Изображения + ├── icons/ # Иконки + ├── fonts/ # Шрифты + └── video/ # Видео +``` + +**Плохо** +```text +// Плохо: слои смешаны, нет понятных границ и публичного API. +src/ +├── components/ +├── api/ +├── styles/ +└── user.ts +``` + +## Правила организации + +- Каждый слой и модуль хранится в собственной папке. +- Внутренние реализации разделяются на `ui`, `model`, `lib`, `api`. +- Публичный API модуля объявляется в `index.ts`. +- Внутренние файлы не импортируются напрямую извне. +- Не смешивать ответственность разных слоёв в одном модуле.