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: Stil Veileder
|
|
image: /images/user-guide/notes/notes_header.png
|
|
---
|
|
|
|
<Frame>
|
|
<img src="/images/user-guide/notes/notes_header.png" alt="Header" />
|
|
</Frame>
|
|
|
|
Dette dokumentet inkluderer reglene som skal følges når man skriver kode.
|
|
|
|
Målet her er å ha en konsekvent kodebase som er enkel å lese og vedlikeholde.
|
|
|
|
For dette er det bedre å være litt mer omstendelig enn å være for konsis.
|
|
|
|
Husk alltid at folk leser kode oftere enn de skriver den, spesielt i et åpen kildekodeprosjekt, hvor hvem som helst kan bidra.
|
|
|
|
Det er mange regler som ikke er definert her, men som sjekkes automatisk av lintverktøy.
|
|
|
|
## React
|
|
|
|
### Bruk funksjonelle komponenter
|
|
|
|
Bruk alltid TSX funksjonelle komponenter.
|
|
|
|
Ikke bruk standard `import` med `const`, fordi det er vanskeligere å lese og vanskeligere å importere med kodefullføring.
|
|
|
|
```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>;
|
|
};
|
|
```
|
|
|
|
### Props
|
|
|
|
Create the type of the props and call it `(ComponentName)Props` if there's no need to export it.
|
|
|
|
Bruk destructuring av 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>;
|
|
```
|
|
|
|
#### Unngå å bruke `React.FC` eller `React.FunctionComponent` for å definere proptype
|
|
|
|
```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 Enkel Variabel Prop Spredning i JSX Elementer
|
|
|
|
Unngå å bruke enkel variabel prop spredning i JSX elementer, som `{...props}`. Denne praksisen resulterer ofte i kode som er mindre leselig og vanskeligere å vedlikeholde fordi det er uklart hvilke props komponenten mottar.
|
|
|
|
```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 }} />;
|
|
};
|
|
```
|
|
|
|
Begrunnelse:
|
|
|
|
- Ved et øyekast er det tydeligere hvilke props koden videresender, noe som gjør det lettere å forstå og vedlikeholde.
|
|
- Det hjelper å forhindre tett kobling mellom komponenter via deres props.
|
|
- Lintverktøy gjør det lettere å identifisere feilstavede eller ubrukte props når du lister opp props eksplisitt.
|
|
|
|
## JavaScript
|
|
|
|
### Bruk nullish-coalescing operator `??`
|
|
|
|
```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';
|
|
```
|
|
|
|
### Bruk valgfri chaining `?.`
|
|
|
|
```tsx
|
|
// ❌ Bad
|
|
onClick && onClick();
|
|
|
|
// ✅ Good
|
|
onClick?.();
|
|
```
|
|
|
|
## TypeScript
|
|
|
|
### Bruk `type` i stedet for `interface`
|
|
|
|
Bruk alltid `type` i stedet for `interface`, fordi de nesten alltid overlapper, og `type` er mer fleksibelt.
|
|
|
|
```tsx
|
|
// ❌ Bad
|
|
interface MyInterface {
|
|
name: string;
|
|
}
|
|
|
|
// ✅ Good
|
|
type MyType = {
|
|
name: string;
|
|
};
|
|
```
|
|
|
|
### Bruk strengbokstaver i stedet for enums
|
|
|
|
[Strengbokstaver](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#literal-types) er måten å håndtere enum-lignende verdier i TypeScript. De er lettere å utvide med Pick og Omit, og gir en bedre utvikleropplevelse, særlig med kodefullføring.
|
|
|
|
Du kan se hvorfor TypeScript anbefaler å unngå enums [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 bruke enums som GraphQL codegen genererer.
|
|
|
|
Det er også bedre å bruke en enum når man bruker et internt bibliotek, slik at det interne biblioteket ikke må eksponere en strengbokstavtype som ikke er relatert til den interne API-en.
|
|
|
|
Eksempel:
|
|
|
|
```TSX
|
|
const {
|
|
setHotkeyScopeAndMemorizePreviousScope,
|
|
goBackToPreviousHotkeyScope,
|
|
} = usePreviousHotkeyScope();
|
|
|
|
setHotkeyScopeAndMemorizePreviousScope(
|
|
RelationPickerHotkeyScope.RelationPicker,
|
|
);
|
|
```
|
|
|
|
## Stilsetting
|
|
|
|
### Bruk StyledComponents
|
|
|
|
Style komponentene 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;
|
|
`;
|
|
```
|
|
|
|
Forankre styled komponentene med "Styled" for å skille dem fra "virkelige" komponenter.
|
|
|
|
```tsx
|
|
// ❌ Bad
|
|
const Title = styled.div`
|
|
color: red;
|
|
`;
|
|
```
|
|
|
|
```tsx
|
|
// ✅ Good
|
|
const StyledTitle = styled.div`
|
|
color: red;
|
|
`;
|
|
```
|
|
|
|
### Tematisering
|
|
|
|
Å bruke temaet til hoveddelen av komponentstilingen er den foretrukne tilnærmingen.
|
|
|
|
#### Måleenheter
|
|
|
|
Unngå å bruke `px` eller `rem` verdier direkte i styled komponenter. De nødvendige verdiene er vanligvis allerede definert i temaet, så det anbefales å benytte temaet for disse formålene.
|
|
|
|
#### Farger
|
|
|
|
Unngå å introdusere nye farger, bruk heller den eksisterende paletten fra temaet. Skulle det være en situasjon der paletten ikke stemmer, vennligst legg igjen en kommentar slik at teamet kan rette det opp.
|
|
|
|
```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åndheve Ingen-Type Importer
|
|
|
|
Unngå type importeringer. For å håndheve denne standarden sjekker en ESLint-regel type importeringer og rapporterer eventuelle brudd. Dette hjelper med å opprettholde konsistens og lesbarhet 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 Importer
|
|
|
|
- **Konsistens**: Ved å unngå type importeringer og bruke en enkelt tilnærming for både type- og verdimporteringer holder kodebasen seg konsekvent i sin modulimportstil.
|
|
|
|
- **Lesbarhet**: Ingen-type importeringer forbedrer kodelesbarhet ved å gjøre det tydelig når du importerer verdier eller typer. Dette reduserer tvetydighet og gjør det lettere å forstå hensikten med importerte 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. This rule will generate errors or warnings for any type import violations.
|
|
|
|
Please note that this rule specifically addresses rare edge cases where unintentional type imports occur. TypeScript selv fraråder denne praksisen, som nevnt i [TypeScript 3.8 utgivelsesnotater](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 å sikre at koden din overholder denne regelen, må du sørge for å kjøre ESLint som en del av utviklingsarbeidsflyten din.
|