---
title: Посібник зі стилю
image: /images/user-guide/notes/notes_header.png
---

<Frame>
  <img src="/images/user-guide/notes/notes_header.png" alt="Header" />
</Frame>

Цей документ включає правила, дотримання яких необхідне при написанні коду.

Мета полягає в тому, щоб мати узгоджену кодову базу, яка легко читається і є легкою для підтримки.

Для цього краще бути трохи багатослівним, ніж занадто лаконічним.

Завжди пам'ятайте, що код читають частіше, ніж пишуть, особливо у відкритих проєктах, де будь-хто може внести свій вклад.

Є багато правил, які не визначені тут, але які автоматично перевіряються за допомогою лінтерів.

## React

### Використовуйте функціональні компоненти

Завжди використовуйте функціональні компоненти TSX.

Не використовуйте стандартний `import` з `const`, оскільки важче читати та імпортувати з підтримкою завершення коду.

```tsx
// ❌ Bad, harder to read, harder to import with code completion
const MyComponent = () => {
  return <div>Hello World</div>;
};

export default MyComponent;

// ✅ Good, easy to read, easy to import with code completion
export function MyComponent() {
  return <div>Hello World</div>;
};
```

### Властивості

Створіть тип властивостей і назвіть його `(ComponentName)Props`, якщо немає потреби його експортувати.

Використовуйте деструктуризацію властивостей.

```tsx
// ❌ Bad, no type
export const MyComponent = (props) => <div>Hello {props.name}</div>;

// ✅ Good, type
type MyComponentProps = {
  name: string;
};

export const MyComponent = ({ name }: MyComponentProps) => <div>Hello {name}</div>;
```

#### Утримуйтесь від використання `React.FC` або `React.FunctionComponent` для визначення типів властивостей

```tsx
/* ❌ - Bad, defines the component type annotations with `FC`
 *    - With `React.FC`, the component implicitly accepts a `children` prop
 *      even if it's not defined in the prop type. This might not always be
 *      desirable, especially if the component doesn't intend to render
 *      children.
 */
const EmailField: React.FC<{
  value: string;
}> = ({ value }) => <TextInput value={value} disabled fullWidth />;
```

```tsx
/* ✅ - Good, a separate type (OwnProps) is explicitly defined for the 
 *      component's props
 *    - This method doesn't automatically include the children prop. If
 *      you want to include it, you have to specify it in OwnProps.
 */ 
type EmailFieldProps = {
  value: string;
};

const EmailField = ({ value }: EmailFieldProps) => (
  <TextInput value={value} disabled fullWidth />
);
```

#### Відсутність одиночного розповсюдження змінних властивостей у JSX-елементах

Уникайте використання одиночного розповсюдження змінних як `{...props}` у JSX-елементах. Ця практика часто призводить до того, що код стає менш читабельним та важчим для підтримки, оскільки незрозуміло, які саме властивості отримує компонент.

```tsx
/* ❌ - Bad, spreads a single variable prop into the underlying component
 */
const MyComponent = (props: OwnProps) => {
  return <OtherComponent {...props} />;
}
```

```tsx
/* ✅ - Good, Explicitly lists all props
 *    - Enhances readability and maintainability
 */ 
const MyComponent = ({ prop1, prop2, prop3 }: MyComponentProps) => {
  return <OtherComponent {...{ prop1, prop2, prop3 }} />;
};
```

Обґрунтування:

- На перший погляд, зрозуміліше, які властивості код передає далі, що полегшує розуміння та підтримку.
- Це допомагає уникнути тісного пов'язування компонентів через їх властивості.
- Інструменти лінтингу полегшують виявлення помилково написаних чи невикористаних властивостей, коли ви вказуєте їх чітко.

## JavaScript

### Використовуйте оператор `??` для нульових льнувачів

```tsx
// ❌ Bad, can return 'default' even if value is 0 or ''
const value = process.env.MY_VALUE || 'default';

// ✅ Good, will return 'default' only if value is null or undefined
const value = process.env.MY_VALUE ?? 'default';
```

### Використовуйте опціональне зчеплення `?.`

```tsx
// ❌ Bad 
onClick && onClick();

// ✅ Good
onClick?.();
```

## TypeScript

### Використовуйте `type` замість `interface`

Завжди використовуйте `type` замість `interface`, тому що вони майже завжди перетинаються, і `type` більш гнучкий.

```tsx
// ❌ Bad
interface MyInterface {
  name: string;
}

// ✅ Good
type MyType = {
  name: string;
};
```

### Використовуйте літерали рядків замість перерахувань

[Літерали рядків](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#literal-types) є основним способом обробки значень подібних до перерахувань в TypeScript. Вони легше розширюються за допомогою Pick і Omit, а також пропонують кращий досвід розробників, особливо з автозавершенням коду.

Ви можете дізнатися, чому TypeScript рекомендує уникати перерахувань [тут](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#enums).

```tsx
// ❌ Bad, utilizes an enum
enum Color {
  Red = "red",
  Green = "green",
  Blue = "blue",
}

let color = Color.Red;
```

```tsx
// ✅ Good, utilizes a string literal

let color: "red" | "green" | "blue" = "red";
```

#### GraphQL та внутрішні бібліотеки

Ви повинні використовувати перерахування, які генерує кодоген GraphQL.

Також краще використовувати перерахування, коли ви використовуєте внутрішню бібліотеку, щоб внутрішня бібліотека не повинна була розкривати тип літерала рядка, який не стосується внутрішнього API.

Приклад:

```TSX
const {
  setHotkeyScopeAndMemorizePreviousScope,
  goBackToPreviousHotkeyScope,
} = usePreviousHotkeyScope();

setHotkeyScopeAndMemorizePreviousScope(
  RelationPickerHotkeyScope.RelationPicker,
);
```

## Стилізація

### Використовуйте StyledComponents

Стилізуйте компоненти з [styled-components](https://emotion.sh/docs/styled).

```tsx
// ❌ Bad
<div className="my-class">Hello World</div>
```

```tsx
// ✅ Good
const StyledTitle = styled.div`
  color: red;
`;
```

Префіксуйте стилізовані компоненти "Styled", щоб відрізняти їх від "реальних" компонентів.

```tsx
// ❌ Bad
const Title = styled.div`
  color: red;
`;
```

```tsx
// ✅ Good
const StyledTitle = styled.div`
  color: red;
`;
```

### Тематизація

Використання теми для більшості стилізацій компонентів є рекомендованим підходом.

#### Одиниці вимірювання

Уникайте використання значень `px` або `rem` безпосередньо в стилізованих компонентах. Необхідні значення зазвичай вже визначені в темі, тому рекомендується використовувати тему для цих цілей.

#### Кольори

Утримуйтеся від введення нових кольорів; натомість використовуйте існуючу палітру з теми. Якщо виникла ситуація, коли палітра не відповідає, залиште коментар, щоб команда могла виправити це.

```tsx
// ❌ Bad, directly specifies style values without utilizing the theme
const StyledButton = styled.button`
  color: #333333;
  font-size: 1rem;
  font-weight: 400;
  margin-left: 4px;
  border-radius: 50px;
`;
```

```tsx
// ✅ Good, utilizes the theme
const StyledButton = styled.button`
  color: ${({ theme }) => theme.font.color.primary};
  font-size: ${({ theme }) => theme.font.size.md};
  font-weight: ${({ theme }) => theme.font.weight.regular};
  margin-left: ${({ theme }) => theme.spacing(1)};
  border-radius:  ${({ theme }) => theme.border.rounded};
`;
```

## Заборона імпорту типів

Уникайте імпорту типів. Щоб забезпечити цю норму, правило ESLint перевіряє і повідомляє про будь-які імпорти типів. Це допомагає підтримувати консистентність і читабельність коду TypeScript.

```tsx
// ❌ Bad
import { type Meta, type StoryObj } from '@storybook/react';

// ❌ Bad
import type { Meta, StoryObj } from '@storybook/react';

// ✅ Good
import { Meta, StoryObj } from '@storybook/react';
```

### Чому заборонено імпорти типів

- **Консистентність**: Уникаючи імпорту типів і використовуючи єдиний підхід до імпорту для обох типів та значень, кодова база залишається консистентною у стилі імпорту модулів.

- **Читабельність**: Імпорти без типів покращують читабельність коду, роблячи його зрозумілим, коли ви імпортуєте значення або типи. Це знижує неоднозначність і спрощує розуміння мети імпортованих символів.

- **Maintainability**: It enhances codebase maintainability because developers can identify and locate type-only imports when reviewing or modifying code.

### Правило ESLint

Правило ESLint, `@typescript-eslint/consistent-type-imports`, забезпечує стандарт без імпорту типів. Це правило генерує помилки або попередження за будь-які порушення імпорту типів.

Зазначте, що це правило спеціально стосується рідкісних випадків, коли ненавмисний імпорт типів відбувається. Сам TypeScript не рекомендує цю практику, як згадується в [примітках до версії TypeScript 3.8](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html). У більшості ситуацій вам не потрібно використовувати імпорт тільки для типів.

To ensure your code complies with this rule, make sure to run ESLint as part of your development workflow.
