Created by Github action --------- Co-authored-by: Crowdin Bot <support+bot@crowdin.com> Co-authored-by: github-actions <github-actions@twenty.com>
296 lines
8.9 KiB
Plaintext
296 lines
8.9 KiB
Plaintext
---
|
|
title: Przewodnik Stylu
|
|
image: /images/user-guide/notes/notes_header.png
|
|
---
|
|
|
|
<Frame>
|
|
<img src="/images/user-guide/notes/notes_header.png" alt="Header" />
|
|
</Frame>
|
|
|
|
Ten dokument zawiera zasady, których należy przestrzegać podczas pisania kodu.
|
|
|
|
Celem jest utrzymanie spójnej bazy kodu, która jest łatwa do czytania i łatwa do utrzymania.
|
|
|
|
W tym przypadku lepiej być nieco bardziej rozwlekłym niż zbyt zwięzłym.
|
|
|
|
Pamiętaj, że kod jest częściej czytany niż pisany, zwłaszcza w projekcie open source, gdzie każdy może przyczynić się do jego rozwoju.
|
|
|
|
There are a lot of rules that are not defined here, but that are automatically checked by linters.
|
|
|
|
## React
|
|
|
|
### Używaj komponentów funkcyjnych
|
|
|
|
Zawsze używaj komponentów funkcyjnych TSX.
|
|
|
|
Nie używaj domyślnego `import` z `const`, ponieważ trudniej go czytać i utrudnia import z automatycznym uzupełnianiem kodu.
|
|
|
|
```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>;
|
|
};
|
|
```
|
|
|
|
### Właściwości (Props)
|
|
|
|
Utwórz typ propsów i nazwij go `(ComponentName)Props`, jeśli nie ma potrzeby eksportowania ich.
|
|
|
|
Używaj destrukturyzacji propsów.
|
|
|
|
```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>;
|
|
```
|
|
|
|
#### Powstrzymaj się od używania `React.FC` lub `React.FunctionComponent`, aby definiować typy propów
|
|
|
|
```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 />
|
|
);
|
|
```
|
|
|
|
#### Brak rozprowadzania pojedynczych zmiennych-propów w elementach JSX
|
|
|
|
Unikaj używania rozprowadzania pojedynczych zmiennych-propów w elementach JSX, takich jak `{...props}`. Ten sposób często prowadzi do kodu, który jest mniej czytelny i trudniejszy do utrzymania, ponieważ nie jest jasne, jakie propy przyjmuje komponent.
|
|
|
|
```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 }} />;
|
|
};
|
|
```
|
|
|
|
Uzasadnienie:
|
|
|
|
- Na pierwszy rzut oka jest widoczne, jakie propy są przekazywane przez kod, co ułatwia jego zrozumienie i konserwację.
|
|
- Pomaga to zapobiegać ścisłemu powiązaniu pomiędzy komponentami poprzez ich propy.
|
|
- Narzędzia do lintowania ułatwiają identyfikację błędnie napisanych lub nieużywanych propów, gdy wyraźnie wymienisz propy.
|
|
|
|
## JavaScript
|
|
|
|
### Używaj operatora współinicjalizującego `??`
|
|
|
|
```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';
|
|
```
|
|
|
|
### Używaj opcjonalnych łańcuchów `?.`
|
|
|
|
```tsx
|
|
// ❌ Bad
|
|
onClick && onClick();
|
|
|
|
// ✅ Good
|
|
onClick?.();
|
|
```
|
|
|
|
## TypeScript
|
|
|
|
### Używaj `type` zamiast `interface`
|
|
|
|
Zawsze używaj `type` zamiast `interface`, ponieważ prawie zawsze się pokrywają, a `type` jest bardziej elastyczny.
|
|
|
|
```tsx
|
|
// ❌ Bad
|
|
interface MyInterface {
|
|
name: string;
|
|
}
|
|
|
|
// ✅ Good
|
|
type MyType = {
|
|
name: string;
|
|
};
|
|
```
|
|
|
|
### Używaj literałów stringowych zamiast enumeracji
|
|
|
|
[Literały stringowe](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#literal-types) są najlepszym sposobem na obsługę wartości podobnych do enumeracji w TypeScript. Są łatwiejsze do rozszerzenia przy użyciu Pick i Omit, oferując lepsze doświadczenie programistyczne, szczególnie przy automatycznym uzupełnianiu kodu.
|
|
|
|
Możesz zobaczyć, dlaczego TypeScript zaleca unikanie enumeracji [tutaj](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 i biblioteki wewnętrzne
|
|
|
|
Powinieneś używać enumeracji generowanych przez kodowanie GraphQL.
|
|
|
|
Lepiej jest również używać enumeracji podczas korzystania z biblioteki wewnętrznej, aby nie musiała ona udostępniać typu literału stringowego, który nie jest związany z wewnętrznym API.
|
|
|
|
Przykład:
|
|
|
|
```TSX
|
|
const {
|
|
setHotkeyScopeAndMemorizePreviousScope,
|
|
goBackToPreviousHotkeyScope,
|
|
} = usePreviousHotkeyScope();
|
|
|
|
setHotkeyScopeAndMemorizePreviousScope(
|
|
RelationPickerHotkeyScope.RelationPicker,
|
|
);
|
|
```
|
|
|
|
## Stylizacja
|
|
|
|
### Używaj StyledComponents
|
|
|
|
Styluj komponenty za pomocą [styled-components](https://emotion.sh/docs/styled).
|
|
|
|
```tsx
|
|
// ❌ Bad
|
|
<div className="my-class">Hello World</div>
|
|
```
|
|
|
|
```tsx
|
|
// ✅ Good
|
|
const StyledTitle = styled.div`
|
|
color: red;
|
|
`;
|
|
```
|
|
|
|
Dodaj "Styled" przed nazwę stylowanym komponentom, aby odróżnić je od rzeczywistych komponentów.
|
|
|
|
```tsx
|
|
// ❌ Bad
|
|
const Title = styled.div`
|
|
color: red;
|
|
`;
|
|
```
|
|
|
|
```tsx
|
|
// ✅ Good
|
|
const StyledTitle = styled.div`
|
|
color: red;
|
|
`;
|
|
```
|
|
|
|
### Tematyka
|
|
|
|
Preferowane podejście to korzystanie z motywu przy stylizacji większości komponentów.
|
|
|
|
#### Jednostki miar
|
|
|
|
Unikaj używania bezpośrednich wartości `px` lub `rem` w stylowanych komponentach. Potrzebne wartości są zazwyczaj już zdefiniowane w motywie, więc zaleca się korzystanie z niego do tych celów.
|
|
|
|
#### Kolory
|
|
|
|
Powstrzymaj się od wprowadzania nowych kolorów; zamiast tego używaj istniejącej palety z motywu. Jeśli przypadkiem paleta nie pasuje, prosimy o zostawienie komentarza, aby zespół mógł to naprawić.
|
|
|
|
```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};
|
|
`;
|
|
```
|
|
|
|
## Egzekwowanie importów bez typów
|
|
|
|
Unikaj importów typów. Aby egzekwować ten standard, reguła ESLint sprawdza i raportuje każde naruszenie importu typu. To pomaga zachować spójność i czytelność kodu 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';
|
|
```
|
|
|
|
### Dlaczego brak importów typów
|
|
|
|
- **Spójność**: Unikanie importów typu i używanie jednolitych podejść do importu typów i wartości, pozwala na zachowanie spójności w stylach importów modułów wewnątrz bazy kodu.
|
|
|
|
- **Czytelność**: Importy bez typów poprawiają czytelność kodu, jasno określając, kiedy importujesz wartości lub typy. Zmniejsza to niejednoznaczność i ułatwia zrozumienie celu importowanych symboli.
|
|
|
|
- **Maintainability**: It enhances codebase maintainability because developers can identify and locate type-only imports when reviewing or modifying code.
|
|
|
|
### Reguła ESLint
|
|
|
|
Reguła ESLint, `@typescript-eslint/consistent-type-imports`, wymusza standard importów bez typów. Ta reguła generuje błędy lub ostrzeżenia dla każdego naruszenia importu typu.
|
|
|
|
Należy zauważyć, że ta reguła dotyczy rzadkich przypadków brzegowych, gdy występują niezamierzone importy typu. TypeScript sam odradza tę praktykę, co jest wspomniane w [uwagach do wydania TypeScript 3.8](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html). W większości sytuacji nie powinieneś potrzebować używać importów tylko-typowych.
|
|
|
|
To ensure your code complies with this rule, make sure to run ESLint as part of your development workflow.
|