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.5 KiB
Plaintext
296 lines
8.5 KiB
Plaintext
---
|
|
title: Stilguide
|
|
image: /images/user-guide/notes/notes_header.png
|
|
---
|
|
|
|
<Frame>
|
|
<img src="/images/user-guide/notes/notes_header.png" alt="Header" />
|
|
</Frame>
|
|
|
|
Dette dokument indeholder reglerne, der skal følges, når du skriver kode.
|
|
|
|
Målet her er at have en konsekvent kodebase, der er let at læse og nem at vedligeholde.
|
|
|
|
Til dette er det bedre at være lidt mere detaljeret end at være for kortfattet.
|
|
|
|
Husk altid, at folk læser koden oftere, end de skriver den, især i et open source projekt, hvor alle kan bidrage.
|
|
|
|
Der er mange regler, der ikke er defineret her, men som automatisk kontrolleres af linters.
|
|
|
|
## React
|
|
|
|
### Brug funktionelle komponenter
|
|
|
|
Brug altid TSX funktionelle komponenter.
|
|
|
|
Brug ikke standard `import` med `const`, da det er sværere at læse og sværere at importere med kodekomplettering.
|
|
|
|
```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>;
|
|
};
|
|
```
|
|
|
|
### Egenskaber
|
|
|
|
Create the type of the props and call it `(ComponentName)Props` if there's no need to export it.
|
|
|
|
Brug destrukturering af 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>;
|
|
```
|
|
|
|
#### Undgå at bruge `React.FC` eller `React.FunctionComponent` til at definere prop typer
|
|
|
|
```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 />
|
|
);
|
|
```
|
|
|
|
#### Ingen Enkeltvariabel Prop Spredning i JSX Elementer
|
|
|
|
Undgå at bruge enkeltvariabel prop spredning i JSX elementer, som `{...props}`. Denne praksis resulterer ofte i kode, der er mindre læselig og sværere at vedligeholde, da det er uklart, hvilke props komponenten modtager.
|
|
|
|
```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 }} />;
|
|
};
|
|
```
|
|
|
|
Begrundelse:
|
|
|
|
- Ved et hurtigt blik er det tydeligere, hvilke props koden sender, hvilket gør det lettere at forstå og vedligeholde.
|
|
- Det hjælper med at forhindre tæt kobling mellem komponenterne via deres props.
|
|
- Linting værktøjer gør det lettere at identificere fejlagtigt stavede eller ubrugte props, når du angiver props eksplicit.
|
|
|
|
## JavaScript
|
|
|
|
### Brug nullish-coalescing operatøren `??`
|
|
|
|
```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';
|
|
```
|
|
|
|
### Brug valgfri kædning `?.`
|
|
|
|
```tsx
|
|
// ❌ Bad
|
|
onClick && onClick();
|
|
|
|
// ✅ Good
|
|
onClick?.();
|
|
```
|
|
|
|
## TypeScript
|
|
|
|
### Brug `type` i stedet for `interface`
|
|
|
|
Brug altid `type` i stedet for `interface`, fordi de næsten altid overlapper, og `type` er mere fleksibel.
|
|
|
|
```tsx
|
|
// ❌ Bad
|
|
interface MyInterface {
|
|
name: string;
|
|
}
|
|
|
|
// ✅ Good
|
|
type MyType = {
|
|
name: string;
|
|
};
|
|
```
|
|
|
|
### Brug strenglitteraler i stedet for enums
|
|
|
|
[Strenglitteraler](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#literal-types) er den foretrukne måde at håndtere enum-lignende værdier i TypeScript. De er lettere at udvide med Pick og Omit, og tilbyder en bedre udvikleroplevelse, især med kodekomplettering.
|
|
|
|
Du kan se, hvorfor TypeScript anbefaler at undgå enum [her](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 og interne biblioteker
|
|
|
|
Du bør bruge enums, som GraphQL codegen genererer.
|
|
|
|
Det er også bedre at bruge en enum, når du bruger et internt bibliotek, så det interne bibliotek ikke behøver at afsløre en strengliteraltype, der ikke er relateret til den interne API.
|
|
|
|
Eksempel:
|
|
|
|
```TSX
|
|
const {
|
|
setHotkeyScopeAndMemorizePreviousScope,
|
|
goBackToPreviousHotkeyScope,
|
|
} = usePreviousHotkeyScope();
|
|
|
|
setHotkeyScopeAndMemorizePreviousScope(
|
|
RelationPickerHotkeyScope.RelationPicker,
|
|
);
|
|
```
|
|
|
|
## Styling
|
|
|
|
### Brug StyledComponents
|
|
|
|
Style komponenterne med [styled-components](https://emotion.sh/docs/styled).
|
|
|
|
```tsx
|
|
// ❌ Bad
|
|
<div className="my-class">Hello World</div>
|
|
```
|
|
|
|
```tsx
|
|
// ✅ Good
|
|
const StyledTitle = styled.div`
|
|
color: red;
|
|
`;
|
|
```
|
|
|
|
Prefix styled components with "Styled" to differentiate them from "real" components.
|
|
|
|
```tsx
|
|
// ❌ Bad
|
|
const Title = styled.div`
|
|
color: red;
|
|
`;
|
|
```
|
|
|
|
```tsx
|
|
// ✅ Good
|
|
const StyledTitle = styled.div`
|
|
color: red;
|
|
`;
|
|
```
|
|
|
|
### Tema
|
|
|
|
Brug af temaet til størstedelen af komponentstylingen er den foretrukne tilgang.
|
|
|
|
#### Måleenheder
|
|
|
|
Undgå at bruge `px` eller `rem` værdier direkte inden for de stilerede komponenter. De nødvendige værdier er generelt allerede defineret i temaet, så det anbefales at benytte temaet til disse formål.
|
|
|
|
#### Farver
|
|
|
|
Undlad at indføre nye farver; brug i stedet den eksisterende palet fra temaet. Skulle der opstå en situation, hvor paletten ikke passer, bedes du efterlade en kommentar, så teamet kan rette det.
|
|
|
|
```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};
|
|
`;
|
|
```
|
|
|
|
## Håndhævelse af Ingen-Type Imports
|
|
|
|
Undgå type imports. For at håndhæve denne standard kontrollerer en ESLint regel enhver type import og rapporterer dem. Dette hjælper med at opretholde konsistens og læsbarhed i TypeScript koden.
|
|
|
|
```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';
|
|
```
|
|
|
|
### Hvorfor Ingen-Type Imports
|
|
|
|
- **Konsistens**: Ved at undgå type imports og bruge en enkelt tilgang til både type og value imports, forbliver kodebasen konsekvent i sin modulimportstil.
|
|
|
|
- **Læsbarhed**: Ingen-type imports forbedrer kode læsbarheden ved at gøre det klart, når du importerer værdier eller typer. Dette reducerer tvetydighed og gør det lettere at forstå formålet med importerede symboler.
|
|
|
|
- **Maintainability**: It enhances codebase maintainability because developers can identify and locate type-only imports when reviewing or modifying code.
|
|
|
|
### ESLint Regel
|
|
|
|
An ESLint rule, `@typescript-eslint/consistent-type-imports`, enforces the no-type import standard. Denne regel vil generere fejl eller advarsler for enhver overtrædelse af type import.
|
|
|
|
Bemærk venligst, at denne regel specifikt adresserer sjældne hjørnetilfælde, hvor utilsigtede type imports opstår. TypeScript selv fraråder denne praksis, som nævnt i [TypeScript 3.8 release notes](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html). In most situations, you should not need to use type-only imports.
|
|
|
|
For at sikre, at din kode overholder denne regel, skal du sørge for at køre ESLint som en del af din udviklingsarbejdsgang.
|