docs: переработать компоненты, структуру проекта и документирование
- переработан раздел «Компоненты»: добавлены правила организации, типизации, реализации - переработан раздел «Структура проекта»: упрощён, добавлены корень репозитория и конфиг-файлы - переработан раздел «Документирование»: добавлены шаблоны для функций, компонентов, типов - обновлён CONTRIBUTING.md: добавлены секции Workflow и Чеклист, правила разделены на Реализацию и Организацию - перенесены типы компонентов из «Типизации» в «Компоненты» - обновлён шаблон генерации: деструктуризация пропсов в теле, children вместо текста - добавлен SCREAMING_SNAKE_CASE для ключей enum в «Именование» - перемещён «Настройка VS Code» в конец сайдбара - обновлён порядок файлов в concat-md.js и перегенерирован RULES.md
This commit is contained in:
@@ -1,10 +1,20 @@
|
||||
---
|
||||
title: UI и компоненты
|
||||
title: Компоненты
|
||||
---
|
||||
|
||||
# UI и компоненты
|
||||
# Компоненты
|
||||
|
||||
Раздел описывает правила создания UI‑компонентов. Эти правила обязательны для всех слоёв FSD: `app`, `screens`, `layouts`, `widgets`, `features`, `entities`, `shared`.
|
||||
Правила написания React-компонентов: файловая структура модуля, типизация пропсов, документирование и реализация. Раздел охватывает компоненты всех слоёв — от `shared/ui` до `screens`.
|
||||
|
||||
Архитектурные слои и их назначение описаны в разделе [Архитектура](/basics/architecture).
|
||||
|
||||
|
||||
## Правила организации
|
||||
|
||||
1. Один компонент — один файл.
|
||||
2. Компонент не содержит бизнес-логики — логика и сайд-эффекты выносятся в хуки или сторы.
|
||||
3. Дочерние компоненты размещаются в сегменте `ui/` и подчиняются тем же правилам структуры.
|
||||
4. Публичный API модуля — только `index.ts`. Прямые импорты внутренних файлов запрещены.
|
||||
|
||||
## Базовая структура компонента
|
||||
|
||||
@@ -20,26 +30,48 @@ container/
|
||||
└── index.ts
|
||||
```
|
||||
|
||||
## Пример базового компонента
|
||||
## Именования
|
||||
|
||||
`styles/container.module.css`
|
||||
```scss
|
||||
.root {}
|
||||
```
|
||||
В CSS Modules использование имени класса **.root** — это общепринятое соглашение (best practice)
|
||||
- Имя корневого css класса всегда `.root`
|
||||
- Интерфейс именуется `{ComponentName}Props`.
|
||||
|
||||
## Типизация
|
||||
|
||||
- Компонент типизируется через `FC<Props>`.
|
||||
- Интерфейс пропсов наследует HTML-атрибуты своего корневого элемента.
|
||||
- `children` отдельно не объявляется — приходит из `HTMLAttributes`.
|
||||
|
||||
## Реализация
|
||||
|
||||
- Пропсы деструктурируются в теле компонента, не в параметрах.
|
||||
- Порядок: пользовательские → системные (`children`, `className`) → `...htmlAttr`.
|
||||
- `className` объединяется с корневым классом через `cl()`: `cl(styles.root, className)`.
|
||||
- `...htmlAttr` прокидывается на корневой элемент.
|
||||
|
||||
## Пример
|
||||
|
||||
`container/types/container.interface.ts`
|
||||
|
||||
`types/container.interface.ts`
|
||||
```ts
|
||||
import type { HTMLAttributes } from 'react'
|
||||
|
||||
/**
|
||||
* Параметры контейнера.
|
||||
* Параметры компонента Container.
|
||||
*/
|
||||
export interface ContainerProps extends HTMLAttributes<HTMLDivElement> {}
|
||||
```
|
||||
Интерфес параметров компонента всегда наследует свойства своего тега: div, button, итд..
|
||||
|
||||
`container.tsx`
|
||||
`container/styles/container.module.css`
|
||||
|
||||
```css
|
||||
.root {
|
||||
max-width: var(--content-width);
|
||||
margin: 0 auto;
|
||||
padding: 0 var(--spacing-4);
|
||||
}
|
||||
```
|
||||
|
||||
`container/container.tsx`
|
||||
|
||||
```tsx
|
||||
import type { FC } from 'react'
|
||||
@@ -51,39 +83,23 @@ import styles from './styles/container.module.css'
|
||||
* Контейнер с адаптивной максимальной шириной.
|
||||
*
|
||||
* Используется для:
|
||||
* - ограничения ширины контента
|
||||
* - центрирования содержимого
|
||||
* - построения адаптивной сетки страницы
|
||||
* - обёртки контента страниц с ограничением ширины
|
||||
* - центрирования блоков в лейауте
|
||||
*/
|
||||
export const Container: FC<ContainerProps> = ({ className, ...htmlAttr }) => {
|
||||
export const Container: FC<ContainerProps> = (props) => {
|
||||
const { children, className, ...htmlAttr } = props
|
||||
|
||||
return (
|
||||
<div {...htmlAttr} className={cl(styles.root, className)}>
|
||||
Container...
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
- Компонент объявляется через `const` и экспортируется именованно.
|
||||
- Пропсы деструктурируются в сигнатуре; если их больше двух — деструктуризацию переносим в тело компонента.
|
||||
- Из пропсов отдельно извлекаются `className` и `...htmlAttr`, чтобы корректно объединять классы и прокидывать остальные атрибуты.
|
||||
- `cl` — короткое имя функции для конкатенации CSS‑классов.
|
||||
- `FC<>` используется для декларации `children`.
|
||||
|
||||
`index.ts`
|
||||
`container/index.ts`
|
||||
|
||||
```ts
|
||||
export { Container } from './container'
|
||||
```
|
||||
|
||||
## Шаблоны и генерация кода
|
||||
|
||||
Создание компонентов — **только через шаблоны**. Ручное создание файловой структуры компонента запрещено. Это обеспечивает единообразие каркаса, одинаковые папки и имена файлов, уменьшает ручные ошибки и ускоряет старт работы.
|
||||
|
||||
После генерации через **@gromlab/create** — проверить название компонента/файлов и заполнить описание назначения. Подробный порядок действий и перечень обязательных шаблонов — в разделе «Workflow».
|
||||
|
||||
## Вложенные (дочерние) компоненты
|
||||
|
||||
Если для реализации функционала нужны компоненты, которые используются только внутри текущего компонента, создавайте их как вложенные в папке `ui/`. Такие компоненты не экспортируются наружу и используются только локально.
|
||||
|
||||
Вложенные компоненты подчиняются тем же правилам по структуре, именованию и стилю (включая папку `styles/` для их стилей).
|
||||
|
||||
@@ -4,146 +4,96 @@ title: Структура проекта
|
||||
|
||||
# Структура проекта
|
||||
|
||||
Раздел описывает базовую структуру проекта Next.js (App Router) и принципы организации модулей на уровне папок и файлов.
|
||||
Раздел описывает расположение файлов и папок в проекте Next.js (App Router).
|
||||
|
||||
## Базовая структура проекта
|
||||
## Корень репозитория
|
||||
|
||||
```text
|
||||
project-root/
|
||||
├── .templates/ # Шаблоны для генерации модулей
|
||||
├── .vscode/ # Настройки и рекомендуемые расширения VS Code
|
||||
├── public/ # Статика, доступная по прямому URL
|
||||
├── src/ # Исходный код приложения
|
||||
├── .env.example # Переменные окружения проекта (шаблон)
|
||||
├── .env # Переменные окружения проекта (не коммитить)
|
||||
├── .gitignore
|
||||
├── AGENTS.md # Инструкции для AI-агентов
|
||||
├── biome.json # Линтер и форматтер (вместо ESLint + Prettier)
|
||||
├── next.config.ts # Конфигурация Next.js
|
||||
├── package.json # Зависимости и скрипты
|
||||
├── postcss.config.mjs # Конфигурация PostCSS
|
||||
└── tsconfig.json # Конфигурация TypeScript
|
||||
```
|
||||
|
||||
## Папка `public/`
|
||||
|
||||
Хранит статические файлы, которые отдаются по прямому URL без обработки сборщиком:
|
||||
|
||||
```text
|
||||
public/
|
||||
└── og-image.png
|
||||
```
|
||||
|
||||
Компоненты, стили и другой исходный код здесь не размещаются.
|
||||
|
||||
## Папка `src/`
|
||||
|
||||
```text
|
||||
src/
|
||||
├── app/ # Слой app: роутинг, провайдеры, глобальные стили
|
||||
│ ├── providers/ # Провайдеры и обёртки приложения
|
||||
│ ├── styles/ # Глобальные стили, CSS-переменные, custom media
|
||||
│ ├── layout.tsx # Корневой layout (провайдеры, стили, метаданные)
|
||||
│ ├── page.tsx # Главная страница → HomeScreen
|
||||
│ └── profile/
|
||||
│ ├── page.tsx # → ProfileScreen
|
||||
│ └── [id]/
|
||||
│ └── page.tsx # → ProfileDetailScreen
|
||||
├── screens/ # UI-компоненты страниц
|
||||
│ ├── home/
|
||||
│ │ ├── home.screen.tsx
|
||||
│ │ └── index.ts
|
||||
│ └── profile/
|
||||
│ ├── profile.screen.tsx
|
||||
│ └── index.ts
|
||||
├── layouts/ # Общие шаблоны и каркасы страниц
|
||||
│ └── main-layout/
|
||||
│ ├── main-layout.layout.tsx
|
||||
│ └── index.ts
|
||||
├── widgets/ # Крупные блоки интерфейса
|
||||
│ └── header/
|
||||
│ ├── header.widget.tsx
|
||||
│ └── index.ts
|
||||
├── features/ # Пользовательские сценарии
|
||||
│ └── auth-by-email/
|
||||
│ ├── ui/
|
||||
│ │ └── login-form.tsx
|
||||
│ ├── model/
|
||||
│ │ └── auth-by-email.store.ts
|
||||
│ ├── auth-by-email.feature.tsx
|
||||
│ └── index.ts
|
||||
├── entities/ # Бизнес-сущности
|
||||
│ └── user/
|
||||
│ ├── model/
|
||||
│ │ └── user.store.ts
|
||||
│ ├── user.entity.tsx
|
||||
│ └── index.ts
|
||||
└── shared/ # Общие ресурсы проекта
|
||||
├── ui/ # Повторно используемые UI-элементы
|
||||
│ └── icon/
|
||||
│ ├── styles/
|
||||
│ │ └── icon.module.css
|
||||
│ ├── types/
|
||||
│ │ └── icon.interface.ts
|
||||
│ ├── icon.tsx
|
||||
│ └── index.ts
|
||||
├── lib/ # Утилиты и хелперы
|
||||
├── services/ # Общие сервисы и клиенты
|
||||
├── config/ # Общие конфигурации и константы
|
||||
└── assets/ # Ресурсы
|
||||
├── images/
|
||||
├── icons/
|
||||
├── fonts/
|
||||
└── video/
|
||||
├── app/ # Роутинг Next.js, провайдеры, глобальные стили
|
||||
├── screens/ # Собраные страницы (UI)
|
||||
├── layouts/ # Шаблоны
|
||||
├── widgets/ # Крупные самостоятельные блоки интерфейса
|
||||
├── features/ # Пользовательские сценарии
|
||||
├── entities/ # Бизнес-сущности
|
||||
└── shared/ # Переиспользуемый код (UI, утилиты, типы и др.)
|
||||
```
|
||||
|
||||
## Слой `app/`
|
||||
Принципы организации слоёв описаны в разделе [Архитектура](../basics/architecture).
|
||||
|
||||
Папка `app/` совмещает две роли: инициализация приложения (провайдеры, глобальные стили) и файловый роутинг Next.js (route-сегменты, `layout.tsx`, `page.tsx`).
|
||||
### Папка `app/`
|
||||
|
||||
- `providers/` и `styles/` -- это инфраструктура приложения, они не являются частью роутинга.
|
||||
- Route-сегменты (вложенные папки с `page.tsx`) -- это роутинг Next.js. Они не содержат логики, только импортируют экраны из `screens/`.
|
||||
Совмещает два слоя: инициализацию приложения по FSD (провайдеры, глобальные стили) и файловый роутинг Next.js (`layout.tsx`, `page.tsx`, route-сегменты).
|
||||
|
||||
Компоненты, хуки, стили и утилиты не размещаются внутри route-сегментов -- всё это живёт в соответствующих слоях FSD.
|
||||
|
||||
## Правила организации
|
||||
|
||||
- В слоях FSD (`features`, `entities`, `widgets`, `screens` и т.д.) `ui/` используется только для дочерних элементов, которые относятся к модулю и не экспортируются отдельно. Главные компоненты, которые составляют сам слой, держат собственные `*.feature.tsx`, `*.widget.tsx` и т. п., а `ui/` служит для вспомогательных мелких компонентов.
|
||||
- В `shared/ui/` хранятся базовые UI-элементы/компоненты, которыми пользуются сразу несколько модулей; в этом случае они экспортируются наружу и не считаются «дочерними» для слоя.
|
||||
- Если модуль строится вокруг «главного» компонента (`*.feature.tsx`, `*.screen.tsx`, `*.widget.tsx`), помещайте его в корень модуля и экспортируйте через `index.ts`. Проверяйте, что `ui/` не используется просто как «контейнер» слоя.
|
||||
- Каждый слой и модуль хранится в собственной папке.
|
||||
- Внутренние реализации разделяются на `ui/`, `model/`, `styles/`, `helpers/`, `lib/`, `api/`.
|
||||
- Публичный API модуля объявляется в `index.ts`.
|
||||
- Внутренние файлы не импортируются напрямую извне.
|
||||
- Не смешивать ответственность разных слоёв в одном модуле.
|
||||
|
||||
## Пример организации структуры
|
||||
|
||||
**Плохо** -- плоская структура без архитектуры:
|
||||
```text
|
||||
src/
|
||||
├── components/
|
||||
│ ├── Header.tsx
|
||||
│ ├── LoginForm.tsx
|
||||
│ ├── UserCard.tsx
|
||||
│ └── Button.tsx
|
||||
├── hooks/
|
||||
│ ├── useAuth.ts
|
||||
│ └── useUser.ts
|
||||
├── api/
|
||||
│ ├── auth.ts
|
||||
│ └── user.ts
|
||||
├── styles/
|
||||
│ ├── header.module.css
|
||||
│ └── login.module.css
|
||||
├── types/
|
||||
│ └── user.ts
|
||||
└── utils/
|
||||
└── format.ts
|
||||
src/app/
|
||||
├── providers/ # Провайдеры приложения
|
||||
├── styles/ # Глобальные стили
|
||||
├── layout.tsx # Корневой layout
|
||||
└── page.tsx # Главная страница
|
||||
```
|
||||
|
||||
Нет слоёв, нет границ ответственности -- Header и Button лежат рядом, хотя это разные уровни абстракции. LoginForm знает про API напрямую. При росте проекта `components/` превращается в свалку.
|
||||
## Папка `.templates/`
|
||||
|
||||
Содержит шаблоны для генерации кода. Каждый подкаталог — шаблон отдельного типа модуля:
|
||||
|
||||
**Хорошо** -- та же функциональность в FSD:
|
||||
```text
|
||||
src/
|
||||
├── widgets/
|
||||
│ └── header/
|
||||
│ ├── header.widget.tsx
|
||||
│ └── index.ts
|
||||
├── features/
|
||||
│ └── auth-by-email/
|
||||
│ ├── ui/
|
||||
│ │ └── login-form.tsx
|
||||
│ ├── model/
|
||||
│ │ └── auth.store.ts
|
||||
│ ├── auth-by-email.feature.tsx
|
||||
│ └── index.ts
|
||||
├── entities/
|
||||
│ └── user/
|
||||
│ ├── ui/
|
||||
│ │ └── user-card.tsx
|
||||
│ ├── model/
|
||||
│ │ └── user.store.ts
|
||||
│ ├── user.entity.tsx
|
||||
│ └── index.ts
|
||||
└── shared/
|
||||
├── ui/
|
||||
│ └── button/
|
||||
│ ├── button.tsx
|
||||
│ └── index.ts
|
||||
└── lib/
|
||||
└── format.ts
|
||||
.templates/
|
||||
├── component/ # Шаблон компонента
|
||||
├── screen/ # Шаблон экрана
|
||||
├── layout/ # Шаблон layout
|
||||
├── widget/ # Шаблон виджета
|
||||
├── feature/ # Шаблон фичи
|
||||
├── entity/ # Шаблон сущности
|
||||
└── store/ # Шаблон стора
|
||||
```
|
||||
|
||||
Каждый элемент на своём слое, с публичным API и чёткими границами ответственности.
|
||||
Подробнее о генерации описано в разделе [Шаблоны и генерация кода](./templates-generation).
|
||||
|
||||
## Конфигурационные файлы
|
||||
|
||||
| Файл | Назначение |
|
||||
|---|---|
|
||||
| `next.config.ts` | Настройки Next.js: редиректы, переменные окружения, webpack |
|
||||
| `tsconfig.json` | Настройки TypeScript: пути, строгость, таргет |
|
||||
| `biome.json` | Правила линтера и форматтера Biome |
|
||||
| `postcss.config.mjs` | Подключение PostCSS-плагинов (CSS Modules, custom media) |
|
||||
| `package.json` | Зависимости, версии, npm-скрипты |
|
||||
| `AGENTS.md` | Инструкции для AI-агентов, работающих в проекте |
|
||||
|
||||
## Переменные окружения
|
||||
|
||||
- `.env` — переменные окружения проекта, запрещено коммитить
|
||||
- `.env.example` — шаблон, коммитится в репозиторий
|
||||
|
||||
Переменные с префиксом `NEXT_PUBLIC_` доступны в клиентском коде. Остальные доступны только на сервере.
|
||||
|
||||
@@ -105,10 +105,12 @@ import styles from './styles/{{name.kebabCase}}.module.css'
|
||||
/**
|
||||
* {{name.pascalCase}}.
|
||||
*/
|
||||
export const {{name.pascalCase}}: FC<{{name.pascalCase}}Props> = ({ className, ...htmlAttr }) => {
|
||||
export const {{name.pascalCase}}: FC<{{name.pascalCase}}Props> = (props) => {
|
||||
const { children, className, ...htmlAttr } = props
|
||||
|
||||
return (
|
||||
<div {...htmlAttr} className={cl(styles.root, className)}>
|
||||
{{name.kebabCase}}
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4,61 +4,131 @@ title: Документирование
|
||||
|
||||
# Документирование
|
||||
|
||||
Этот раздел описывает правила документирования кода: когда и как писать комментарии к функциям, компонентам, типам и интерфейсам.
|
||||
Этот раздел описывает правила документирования кода: когда и как писать
|
||||
комментарии к компонентам, функциям, типам и интерфейсам.
|
||||
|
||||
## Правила
|
||||
## Общие правила
|
||||
|
||||
- Документировать только назначение функций, компонентов, типов, интерфейсов и enum.
|
||||
- Не документировать параметры, возвращаемые значения, типы пропсов и очевидные детали.
|
||||
- В интерфейсах, типах и enum описывать только смысл поля или значения.
|
||||
- Описание должно быть кратким, информативным и завершаться точкой.
|
||||
- Документировать публичные функции, компоненты, типы, интерфейсы и enum.
|
||||
- Не документировать очевидное — если название говорит само за себя, комментарий не нужен.
|
||||
- Не документировать параметры, возвращаемые значения и типы пропсов — они видны из сигнатуры.
|
||||
- Описание через пользу и назначение, а не через внутреннюю реализацию.
|
||||
- Описание завершается точкой.
|
||||
|
||||
## Примеры
|
||||
## Функции
|
||||
|
||||
Для документирования функций используется шаблон. Описание механики опционально —
|
||||
добавляется когда логика нетривиальна.
|
||||
|
||||
**Шаблон**
|
||||
```ts
|
||||
/**
|
||||
* <Что делает функция в 1 строке>.
|
||||
*
|
||||
* <Опционально: описание сложной механики или важных нюансов>.
|
||||
*/
|
||||
```
|
||||
|
||||
**Хорошо**
|
||||
```ts
|
||||
/**
|
||||
* Список задач пользователя.
|
||||
* Форматирует цену с символом валюты.
|
||||
*/
|
||||
export const TodoList = memo(() => { ... });
|
||||
export const formatPrice = (value: number): string => { ... }
|
||||
|
||||
/**
|
||||
* Интерфейс задачи.
|
||||
* Рекурсивно собирает дерево категорий из плоского списка.
|
||||
*
|
||||
* Группирует элементы по parentId, начиная с корневых (parentId = null).
|
||||
* Категории без родителя попадают в корень дерева.
|
||||
*/
|
||||
export const buildCategoryTree = (categories: Category[]): CategoryTree[] => { ... }
|
||||
```
|
||||
|
||||
**Плохо**
|
||||
```ts
|
||||
// Плохо: дублирует сигнатуру.
|
||||
/**
|
||||
* @param value - число
|
||||
* @returns строка с ценой
|
||||
*/
|
||||
```
|
||||
|
||||
## Компоненты
|
||||
|
||||
Компонент описывает своё **назначение** и **сценарии применения** — это помогает понять, когда и где его использовать, без необходимости читать реализацию.
|
||||
|
||||
**Шаблон**
|
||||
```ts
|
||||
/**
|
||||
* <Назначение компонента в 1 строке>.
|
||||
*
|
||||
* Используется для:
|
||||
* - <сценарий 1>
|
||||
* - <сценарий 2>
|
||||
* - <сценарий 3>
|
||||
*/
|
||||
```
|
||||
|
||||
**Хорошо**
|
||||
```tsx
|
||||
/**
|
||||
* Контейнер с адаптивной максимальной шириной.
|
||||
*
|
||||
* Используется для:
|
||||
* - обёртки контента страниц с ограничением ширины
|
||||
* - центрирования блоков в лейауте
|
||||
*/
|
||||
export const Container: FC<ContainerProps> = (props) => { ... }
|
||||
```
|
||||
|
||||
**Плохо**
|
||||
```tsx
|
||||
// Плохо: описывает реализацию, а не назначение.
|
||||
/**
|
||||
* Рендерит div с className и htmlAttr.
|
||||
*/
|
||||
|
||||
// Плохо: нет описания вообще.
|
||||
export const Container: FC<ContainerProps> = (props) => { ... }
|
||||
```
|
||||
|
||||
## Типы, интерфейсы, enum
|
||||
|
||||
Документируются назначение сущности и каждое её поле.
|
||||
|
||||
**Хорошо**
|
||||
```ts
|
||||
/**
|
||||
* Фильтры списка задач.
|
||||
*/
|
||||
export enum TodoFilter {
|
||||
/** Все задачи. */
|
||||
ALL = 'all',
|
||||
/** Только активные. */
|
||||
ACTIVE = 'active',
|
||||
/** Только завершённые. */
|
||||
COMPLETED = 'completed',
|
||||
}
|
||||
|
||||
/**
|
||||
* Задача пользователя.
|
||||
*/
|
||||
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 — статус выполнения
|
||||
*/
|
||||
// Плохо: описывает очевидное.
|
||||
export interface TodoItem {
|
||||
/** id — это id */
|
||||
id: string;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -18,6 +18,7 @@ title: Именование
|
||||
| React-компоненты | `PascalCase` |
|
||||
| Хуки | `useSomething` |
|
||||
| CSS классы | `camelCase` |
|
||||
| Ключи enum | `SCREAMING_SNAKE_CASE` |
|
||||
|
||||
|
||||
## Именование файлов
|
||||
|
||||
@@ -13,45 +13,6 @@ title: Типизация
|
||||
- Избегать `any` и `unknown` без необходимости.
|
||||
- Не использовать `ts-ignore`, кроме крайних случаев с явным комментарием причины.
|
||||
|
||||
## Типы для компонентов
|
||||
|
||||
- Типизировать параметры и публичный интерфейс компонента.
|
||||
- Дефолтные значения описывать явно в коде.
|
||||
|
||||
**Хорошо**
|
||||
```tsx
|
||||
/**
|
||||
* Параметры кнопки.
|
||||
*/
|
||||
interface ButtonProps extends HTMLAttributes<HTMLDivElement> {
|
||||
/** Текст кнопки. */
|
||||
label: string;
|
||||
/** Обработчик клика по кнопке. */
|
||||
onClick: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Кнопка с пользовательскими стилями.
|
||||
*/
|
||||
export const Button: FC<ButtonProps> = ({ className, label, onClick, ...htmlAttr }) => {
|
||||
return (
|
||||
<div {...htmlAttr} className={cl(styles.root, className)}>
|
||||
button
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
**Плохо**
|
||||
```tsx
|
||||
// Плохо: параметры не типизированы.
|
||||
export const Button = (props) => (
|
||||
<button type="button" onClick={props.onClick}>
|
||||
{props.label}
|
||||
</button>
|
||||
);
|
||||
```
|
||||
|
||||
## Функции
|
||||
|
||||
- Для публичных функций указывать возвращаемый тип.
|
||||
|
||||
Reference in New Issue
Block a user