--- title: Посібник зі стилю image: /images/user-guide/notes/notes_header.png --- Header Цей документ включає правила, дотримання яких необхідне при написанні коду. Мета полягає в тому, щоб мати узгоджену кодову базу, яка легко читається і є легкою для підтримки. Для цього краще бути трохи багатослівним, ніж занадто лаконічним. Завжди пам'ятайте, що код читають частіше, ніж пишуть, особливо у відкритих проєктах, де будь-хто може внести свій вклад. Є багато правил, які не визначені тут, але які автоматично перевіряються за допомогою лінтерів. ## React ### Використовуйте функціональні компоненти Завжди використовуйте функціональні компоненти TSX. Не використовуйте стандартний `import` з `const`, оскільки важче читати та імпортувати з підтримкою завершення коду. ```tsx // ❌ Bad, harder to read, harder to import with code completion const MyComponent = () => { return
Hello World
; }; export default MyComponent; // ✅ Good, easy to read, easy to import with code completion export function MyComponent() { return
Hello World
; }; ``` ### Властивості Створіть тип властивостей і назвіть його `(ComponentName)Props`, якщо немає потреби його експортувати. Використовуйте деструктуризацію властивостей. ```tsx // ❌ Bad, no type export const MyComponent = (props) =>
Hello {props.name}
; // ✅ Good, type type MyComponentProps = { name: string; }; export const MyComponent = ({ name }: MyComponentProps) =>
Hello {name}
; ``` #### Утримуйтесь від використання `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 }) => ; ``` ```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) => ( ); ``` #### Відсутність одиночного розповсюдження змінних властивостей у JSX-елементах Уникайте використання одиночного розповсюдження змінних як `{...props}` у JSX-елементах. Ця практика часто призводить до того, що код стає менш читабельним та важчим для підтримки, оскільки незрозуміло, які саме властивості отримує компонент. ```tsx /* ❌ - Bad, spreads a single variable prop into the underlying component */ const MyComponent = (props: OwnProps) => { return ; } ``` ```tsx /* ✅ - Good, Explicitly lists all props * - Enhances readability and maintainability */ const MyComponent = ({ prop1, prop2, prop3 }: MyComponentProps) => { return ; }; ``` Обґрунтування: - На перший погляд, зрозуміліше, які властивості код передає далі, що полегшує розуміння та підтримку. - Це допомагає уникнути тісного пов'язування компонентів через їх властивості. - Інструменти лінтингу полегшують виявлення помилково написаних чи невикористаних властивостей, коли ви вказуєте їх чітко. ## 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
Hello World
``` ```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.