Created by Github action --------- Co-authored-by: Crowdin Bot <support+bot@crowdin.com> Co-authored-by: github-actions <github-actions@twenty.com>
296 lines
12 KiB
Plaintext
296 lines
12 KiB
Plaintext
---
|
||
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.
|