Files
upstream-twenty/packages/twenty-docs/l/ru/developers/contribute/capabilities/frontend-development/style-guide.mdx
upstream-mirror e7da97194a
Some checks failed
App Prod-Parity E2E Dispatch / dispatch (push) Failing after 10s
CD Storybook UI / build (push) Failing after 3m25s
CD Storybook UI / dispatch (push) Has been skipped
CD deploy main / website-changed-files (push) Successful in 18m8s
CI Agent Skills / changed-files-check (push) Successful in 18m9s
CI Create App E2E minimal / changed-files-check (push) Successful in 24s
CI Create App / changed-files-check (push) Successful in 26s
CI Docs / changed-files-check (push) Successful in 26s
CI Emails / changed-files-check (push) Successful in 28s
CI Example App Hello World / changed-files-check (push) Successful in 23s
CI Front / changed-files-check (push) Has been skipped
CI Example App Postcard / changed-files-check (push) Successful in 27s
CI UI / changed-files-check (push) Has been skipped
CI Utils Test / changed-files-check (push) Successful in 45s
CI Twenty Apps / discover (push) Successful in 1m3s
CD deploy main / deploy-main (push) Failing after 3s
CI Agent Skills / agent-skills-validate (push) Has been skipped
CI Create App / create-app-test (lint) (push) Has been skipped
CI Emails / emails-test (push) Has been skipped
CI Front / front-task (lingui:compile) (push) Has been skipped
CI Front / front-task (lint) (push) Has been skipped
CI Example App Postcard / example-app-postcard (push) Has been skipped
CI UI / ui-task (lint) (push) Has been skipped
CI UI / ui-task (pack-size) (push) Has been skipped
CI UI / ui-task (size) (push) Has been skipped
CI UI / ui-task (test) (push) Has been skipped
CI UI / ui-task (typecheck) (push) Has been skipped
CI Utils Test / utils-test (push) Has been skipped
CI Twenty Apps / ${{ matrix.app.name }} (push) Has been skipped
CI Emails / ci-emails-status-check (push) Successful in 2s
CI Example App Hello World / ci-example-app-hello-world-status-check (push) Successful in 2s
CI Example App Postcard / ci-example-app-postcard-status-check (push) Successful in 3s
CI UI / ui-sb-test (push) Has been skipped
CI Utils Test / ci-utils-test-status-check (push) Successful in 2s
CI Twenty Apps / ci-twenty-apps-status-check (push) Successful in 2s
CI UI / ci-ui-status-check (push) Successful in 2s
CI Desktop / desktop (push) Failing after 1m8s
Push docs to Crowdin / Push documentation to Crowdin (push) Failing after 55s
Push translations to Crowdin / Extract and upload translations (push) Failing after 5s
Push website translations to Crowdin / Extract and upload website translations (push) Failing after 5s
CI Create App / create-app-test (test) (push) Has been skipped
CI Create App / create-app-test (typecheck) (push) Has been skipped
CI Docs / docs-lint (push) Has been skipped
CI Example App Hello World / example-app-hello-world (push) Has been skipped
CI Front / front-task (lingui:extract) (push) Has been skipped
CI Front / front-task (test) (push) Has been skipped
CI Front / front-task (typecheck) (push) Has been skipped
CI UI / ui-sb-build (push) Failing after 1m32s
CI Twenty Apps / ${{ matrix.app.name }} (${{ matrix.server-source }}) (push) Has been skipped
CI Agent Skills / agent-skills-publish (push) Has been skipped
CI Create App / ci-create-app-status-check (push) Successful in 2s
CI Agent Skills / agent-skills-remote-source (push) Has been skipped
CI Create App E2E minimal / create-app-e2e-minimal (push) Has been cancelled
CI E2E Main / e2e-test (push) Has been cancelled
CI Front / front-sb-build (push) Has been cancelled
CI Front / front-build (push) Has been cancelled
CI Create App E2E minimal / ci-create-app-e2e-minimal-status-check (push) Has been cancelled
CI E2E Main / ci-e2e-main-status-check (push) Has been cancelled
CI E2E Main / notify-main-ci-failure (push) Has been cancelled
CI E2E Main / qa-scout-comment (push) Has been cancelled
CI Front / front-sb-test (push) Has been cancelled
CI Front / front-sb-screenshots (push) Has been cancelled
CI Front / ci-front-status-check (push) Has been cancelled
DPA Sub-Processor Sync / sync-subprocessors (push) Failing after 3s
AI Catalog Sync / sync-catalog (push) Failing after 2s
snapshot of https://github.com/twentyhq/twenty.git (main, 2026-09-17; blobs > 131072B omitted)
2026-09-17 23:28:13 +05:00

292 lines
12 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: Руководство по стилю
icon: paintbrush
---
Этот документ включает правила, которые нужно соблюдать при написании кода.
Цель заключается в обеспечении однородности кода, который будет легко читать и поддерживать.
Для этого лучше быть немного более многословными, чем слишком краткими.
Всегда помните, что код читают чаще, чем пишут, особенно в проекте с открытым исходным кодом, в который может внести вклад кто угодно.
Существует много правил, которые здесь не описаны, но автоматически проверяются линтерами.
## 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-элементах.
Избегайте спреда пропсов из одной переменной в JSX-элементах, например `{...props}`. Подобная практика часто приводит к менее читаемому и сложному в поддержке коду, так как непонятно, какие пропсы принимает компонент.
```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
Стилизуйте компоненты с помощью [Linaria styled](https://github.com/callstack/linaria).
```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};
`;
```
## Запрещение импорта типов
Избегайте импорта типов. Чтобы обеспечить соблюдение этого стандарта, правило Oxlint проверяет и сообщает о любых импортах с ключевым словом type. Это помогает сохранить согласованность и читаемость кода 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';
```
### Почему избегать импорта типов
* **Согласованность**: Избегая импорта типов и используя единый подход для импорта как типов, так и значений, кодовая база остается согласованной в стиле импорта модулей.
* **Читаемость**: Избегающий импорт типов улучшает читаемость кода, делая ясным, когда вы импортируете значения или типы. Это снижает двусмысленность и облегчает понимание назначения импортируемых символов.
* **Поддерживаемость**: Это повышает поддерживаемость кодовой базы, поскольку разработчики могут идентифицировать и находить импорты только типов при просмотре или изменении кода.
### Правило Oxlint
Правило Oxlint `typescript/consistent-type-imports` обеспечивает соблюдение стандарта импортов без ключевого слова type. Это правило создаст ошибки или предупреждения для всех нарушений импорта типов.
Обратите внимание, что это правило касается редких крайних случаев, когда случаются непреднамеренные импорты типов. Сам TypeScript не рекомендует эту практику, как указано в [примечаниях к выпуску TypeScript 3.8](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html). В большинстве случаев вам не нужно использовать импорты только типов.
Чтобы гарантировать соответствие вашего кода этому правилу, убедитесь, что вы запускаете Oxlint как часть вашего рабочего процесса разработки.