docs: отказаться от FC и interface в пропсах компонентов
- переписана типизация: type вместо interface, убран FC - введена система типов: Params + RootAttrs + Props - добавлены обоснования: почему type, почему не FC, почему types/ - обновлены примеры в components, page-level, templates, documentation - убраны упоминания FC из таблиц index.md и README - перегенерированы RULES.md
This commit is contained in:
@@ -25,7 +25,7 @@ container/
|
||||
├── styles/
|
||||
│ └── container.module.css
|
||||
├── types/
|
||||
│ └── container.interface.ts
|
||||
│ └── container.type.ts
|
||||
├── container.tsx
|
||||
└── index.ts
|
||||
```
|
||||
@@ -33,13 +33,17 @@ container/
|
||||
## Именования
|
||||
|
||||
- Имя корневого css класса всегда `.root`
|
||||
- Интерфейс именуется `{ComponentName}Props`.
|
||||
- Тип пропсов именуется `{ComponentName}Props`.
|
||||
- Тип пользовательских параметров именуется `{ComponentName}Params`.
|
||||
|
||||
## Типизация
|
||||
|
||||
- Компонент типизируется через `FC<Props>`.
|
||||
- Интерфейс пропсов наследует HTML-атрибуты своего корневого элемента.
|
||||
- `children` отдельно не объявляется — приходит из `HTMLAttributes`.
|
||||
Структура типов компонента показана в [примере](#пример). Ниже — обоснования ключевых решений.
|
||||
|
||||
- **`type` вместо `interface`** — гибче для пропсов: поддерживает union, intersection, mapped types. Declaration merging пропсам не нужно.
|
||||
- **Без `FC`** — неявно добавляет `children`, усложняет дженерики, не даёт преимуществ перед аннотацией параметра.
|
||||
- **Типы в `types/`, а не в `.tsx`** — предотвращает циклические зависимости (компонент импортирует хук, хук импортирует тип из компонента) и разделяет ответственность: `.tsx` для рендера, `.type.ts` для данных.
|
||||
- **Без возвращаемого типа** — TypeScript выводит из JSX. Осознанное исключение из [базового правила](/basics/typing).
|
||||
|
||||
## Реализация
|
||||
|
||||
@@ -50,7 +54,7 @@ container/
|
||||
|
||||
## Пример
|
||||
|
||||
`container/types/container.interface.ts`
|
||||
`container/types/container.type.ts`
|
||||
|
||||
```ts
|
||||
import type { HTMLAttributes } from 'react'
|
||||
@@ -58,7 +62,12 @@ import type { HTMLAttributes } from 'react'
|
||||
/**
|
||||
* Параметры компонента Container.
|
||||
*/
|
||||
export interface ContainerProps extends HTMLAttributes<HTMLDivElement> {}
|
||||
export type ContainerParams = {}
|
||||
|
||||
/** HTML-атрибуты корневого элемента. */
|
||||
type RootAttrs = HTMLAttributes<HTMLDivElement>
|
||||
|
||||
export type ContainerProps = RootAttrs & ContainerParams
|
||||
```
|
||||
|
||||
`container/styles/container.module.css`
|
||||
@@ -74,9 +83,8 @@ export interface ContainerProps extends HTMLAttributes<HTMLDivElement> {}
|
||||
`container/container.tsx`
|
||||
|
||||
```tsx
|
||||
import type { FC } from 'react'
|
||||
import cl from 'clsx'
|
||||
import type { ContainerProps } from './types/container.interface'
|
||||
import type { ContainerProps } from './types/container.type'
|
||||
import styles from './styles/container.module.css'
|
||||
|
||||
/**
|
||||
@@ -86,7 +94,7 @@ import styles from './styles/container.module.css'
|
||||
* - обёртки контента страниц с ограничением ширины
|
||||
* - центрирования блоков в лейауте
|
||||
*/
|
||||
export const Container: FC<ContainerProps> = (props) => {
|
||||
export const Container = (props: ContainerProps) => {
|
||||
const { children, className, ...htmlAttr } = props
|
||||
|
||||
return (
|
||||
@@ -102,4 +110,3 @@ export const Container: FC<ContainerProps> = (props) => {
|
||||
```ts
|
||||
export { Container } from './container'
|
||||
```
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ export const metadata: Metadata = {
|
||||
description: 'Страница профиля пользователя',
|
||||
}
|
||||
|
||||
interface ProfilePageProps {
|
||||
type ProfilePageProps = {
|
||||
params: Promise<{ id: string }>
|
||||
}
|
||||
|
||||
@@ -47,15 +47,14 @@ export default async function ProfilePage({ params }: ProfilePageProps) {
|
||||
```tsx
|
||||
'use client'
|
||||
|
||||
import type { FC } from 'react'
|
||||
import { ErrorScreen } from '@/screens/error'
|
||||
|
||||
interface ErrorPageProps {
|
||||
type ErrorPageProps = {
|
||||
error: Error & { digest?: string }
|
||||
reset: () => void
|
||||
}
|
||||
|
||||
const ErrorPage: FC<ErrorPageProps> = ({ error, reset }) => {
|
||||
const ErrorPage = ({ error, reset }: ErrorPageProps) => {
|
||||
return <ErrorScreen error={error} reset={reset} />
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ title: Шаблоны и генерация кода
|
||||
│ ├── styles/
|
||||
│ │ └── {{name.kebabCase}}.module.css
|
||||
│ ├── types/
|
||||
│ │ └── {{name.kebabCase}}.interface.ts
|
||||
│ │ └── {{name.kebabCase}}.type.ts
|
||||
│ ├── {{name.kebabCase}}.tsx
|
||||
│ └── index.ts
|
||||
└── store/ # шаблон Zustand стора
|
||||
@@ -86,26 +86,30 @@ export { {{name.pascalCase}} } from './{{name.kebabCase}}'
|
||||
```
|
||||
|
||||
```ts
|
||||
// .templates/component/types/{{name.kebabCase}}.interface.ts
|
||||
// .templates/component/types/{{name.kebabCase}}.type.ts
|
||||
import type { HTMLAttributes } from 'react'
|
||||
|
||||
/**
|
||||
* Параметры {{name.pascalCase}}.
|
||||
*/
|
||||
export interface {{name.pascalCase}}Props extends HTMLAttributes<HTMLDivElement> {}
|
||||
export type {{name.pascalCase}}Params = {}
|
||||
|
||||
/** HTML-атрибуты корневого элемента. */
|
||||
type RootAttrs = HTMLAttributes<HTMLDivElement>
|
||||
|
||||
export type {{name.pascalCase}}Props = RootAttrs & {{name.pascalCase}}Params
|
||||
```
|
||||
|
||||
```tsx
|
||||
// .templates/component/{{name.kebabCase}}.tsx
|
||||
import type { FC } from 'react'
|
||||
import cl from 'clsx'
|
||||
import type { {{name.pascalCase}}Props } from './types/{{name.kebabCase}}.interface'
|
||||
import type { {{name.pascalCase}}Props } from './types/{{name.kebabCase}}.type'
|
||||
import styles from './styles/{{name.kebabCase}}.module.css'
|
||||
|
||||
/**
|
||||
* {{name.pascalCase}}.
|
||||
*/
|
||||
export const {{name.pascalCase}}: FC<{{name.pascalCase}}Props> = (props) => {
|
||||
export const {{name.pascalCase}} = (props: {{name.pascalCase}}Props) => {
|
||||
const { children, className, ...htmlAttr } = props
|
||||
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user