Conventions de codage TypeScript / React¶
Portee¶
Ce document definit les conventions de codage TypeScript et React applicables a tous les projets frontend de l'organisation EIP-MemTide, notamment FrontWeb. Il couvre le nommage, l'architecture, le typage, les patterns React, le formatage et les tests.
Toute contribution (PR, commit, revue) doit etre conforme a ces regles. En cas de doute, ce document fait reference.
Relation avec les regles machine : le fichier
Claude/rules/Typescript/conventions-typescript.mdcontient les memes regles sous forme d'instructions strictes pour les agents IA. Les deux documents doivent rester synchronises.
1. Langue¶
Tout le code, les commentaires, les noms de variables, les noms de fonctions et la documentation doivent etre rediges en anglais americain (U.S. English). Les commentaires ou identifiants en francais sont interdits.
2. Conventions de nommage¶
| Element | Convention | Exemple |
|---|---|---|
| Fichiers composants | PascalCase.tsx |
MemoryDashboard.tsx |
| Fichiers utilitaires | camelCase.ts |
formatUptime.ts |
| Composants React | PascalCase |
HomePage, MemoryBlock |
| Fonctions et variables | camelCase |
formatUptime(), totalBytes |
| Constantes | SCREAMING_SNAKE_CASE |
API_TIMEOUT, MAX_RETRIES |
| Interfaces et types | PascalCase |
MemoryBlock, TopologyData |
| Enums et valeurs d'enum | PascalCase |
TierType, TierType.NumaDram |
| Repertoires | camelCase |
features/, shared/ |
Regles complementaires :
- Fonctions : verbes decrivant l'action (
fetchSnapshot,calculateOffset). Eviterprocess,handle. - Variables et types : noms explicites (
memoryBlocks,numaNodeCount). - Booleens : prefixes
is,has,can,should(isLoading,hasError).
// Mauvais
const data = getStuff();
const flag = true;
// Bon
const numaNodes = fetchTopology();
const isHardwareReady = true;
3. Architecture — Feature-Sliced Design¶
3.1 Couches et sens des imports¶
app --> features --> entities --> shared
| Couche | Responsabilite | Peut importer depuis | Interdit |
|---|---|---|---|
app/ |
Point d'entree, routing, providers, styles globaux | features, entities, shared |
— |
features/ |
Modules fonctionnels autonomes (logique metier + UI) | entities, shared |
Autres features, app |
entities/ |
Types du domaine, helpers purs | shared |
features, app |
shared/ |
Utilitaires generiques, composants UI de base, theme | Rien (sauf npm) | Toutes les couches |
Regle d'or : aucun import lateral entre features. Si deux features partagent de la logique, l'extraire dans entities/ ou shared/.
3.2 Structure d'une feature¶
Chaque feature est organisee en sous-repertoires api/ (clients HTTP, DTOs, mappers), model/ (stores, hooks, machines a etats) et ui/ (composants React, CSS).
3.3 Barrel exports¶
Chaque module expose un index.ts comme point d'entree public :
// entities/memory/index.ts
export type { MemoryBlock, MemorySnapshot } from './types';
// Import depuis le barrel (correct)
import { MemoryBlock } from 'entities/memory';
// Import direct (a eviter)
import { MemoryBlock } from 'entities/memory/types';
3.4 Structure type du projet¶
src/ contient quatre repertoires racines alignes sur les couches FSD : app/ (App.tsx, styles globaux), entities/ (un sous-repertoire par domaine avec types.ts + index.ts), features/ (un sous-repertoire par feature avec api/, model/, ui/), shared/ (assets/, lib/, theme/, ui/).
4. Regles TypeScript¶
4.1 Mode strict¶
tsconfig.json doit activer "strict": true (strictNullChecks, noImplicitAny, strictFunctionTypes, etc.).
4.2 Interdiction de any¶
Utiliser unknown + type guard quand le type est inconnu :
function parse(data: unknown): string {
if (typeof data !== 'string') throw new Error('Expected string');
return data;
}
4.3 Types de retour explicites¶
Obligatoire sur toutes les fonctions exportees : export function formatGiB(bytes: number): string { ... }
4.4 Interface vs Type¶
| Utiliser | Quand |
|---|---|
interface |
Formes d'objets, props de composants, contrats API |
type |
Unions, intersections, types conditionnels, types mappes |
4.5 Unions discriminees¶
Privilegier les unions discriminees pour les etats complexes. Elles eliminent les combinaisons d'etats impossibles :
// MAUVAIS — etats impossibles representables
interface State { isLoading: boolean; isError: boolean; data?: MemorySnapshot; }
// BON — chaque etat est explicite et exhaustif
type State =
| { status: 'idle' }
| { status: 'loading' }
| { status: 'success'; data: MemorySnapshot }
| { status: 'error'; error: string };
4.6 Assertions de type¶
as constpour les objets litteraux non mutables.- Eviter
as Typesauf necessite absolue. Jamais deas any. @ts-ignoreinterdit ;@ts-expect-errortolere uniquement avec commentaire justificatif.
5. Regles React¶
5.1 Composants fonctionnels uniquement¶
Les class components sont interdits. Utiliser exclusivement des fonctions avec hooks :
export function MemoryGrid({ blocks, tierType }: MemoryGridProps): React.ReactElement {
return ( ... );
}
5.2 Un composant par fichier, named export¶
- Chaque
.tsxcontient un seul composant exporte (sous-composants locaux non exportes toleres si < 20 lignes). - Utiliser des named exports, jamais
export defaultpour les composants.
5.3 Props explicites¶
Les interfaces de props sont nommees <ComponentName>Props et les props sont destructurees dans la signature :
interface PidFormProps {
onSubmit: (pid: number) => void;
isLoading: boolean;
}
export function PidForm({ onSubmit, isLoading }: PidFormProps): React.ReactElement { ... }
5.4 Structure d'un fichier composant¶
Ordre recommande :
- Imports (externes, puis internes par couche FSD descendante)
- Interface des props
- Constantes locales
- Le composant (fonction exportee)
import { useState } from 'react';
import { MemoryBlock } from 'entities/memory';
import { Card } from 'shared/ui/Card';
import './dashboard.css';
interface MemoryGridProps { blocks: MemoryBlock[]; tierType: 'dram' | 'cxl'; }
const BLOCK_SIZE_PX = 24;
export function MemoryGrid({ blocks, tierType }: MemoryGridProps): React.ReactElement {
const [selected, setSelected] = useState<number | null>(null);
return ( ... );
}
5.5 Hooks¶
- Appels uniquement au niveau superieur : jamais dans des conditions ou boucles.
- Hooks personnalises prefixes par
use:useMemoryDashboard,useTopologyStore. - Logique metier dans
model/(hooks), affichage dansui/(composants).
5.6 Error Boundaries et Suspense¶
Envelopper les sous-arbres critiques pour la resilience :
<ErrorBoundary fallback={<ErrorBanner message="Something went wrong" />}>
<Suspense fallback={<Loader />}>
<MemoryDashboardPage />
</Suspense>
</ErrorBoundary>
6. Patterns interdits et requis¶
6.1 Patterns interdits¶
| Pattern interdit | Alternative |
|---|---|
any |
Typage precis ou unknown + type guard |
| Class components | Composants fonctionnels + hooks |
var |
const par defaut, let si reassignation |
Inline styles (style={{ ... }}) |
Fichiers CSS, variables CSS |
console.log en production |
Logger structure ou suppression |
default export pour composants |
Named export |
@ts-ignore |
Corriger le type ou @ts-expect-error avec commentaire |
| Import lateral entre features | Extraire vers entities/ ou shared/ |
| Commentaires en francais | Anglais americain uniquement |
6.2 Patterns requis¶
| Pattern requis | Raison |
|---|---|
"strict": true dans tsconfig |
Securite de type maximale |
| Types de retour explicites sur les exports | Auto-documentation, refactoring fiable |
| Unions discriminees pour les etats | Elimination des etats impossibles |
| Props destructurees dans la signature | Lisibilite |
| Error Boundaries sur les sous-arbres critiques | Resilience |
Suspense pour le lazy loading |
UX fluide |
Barrel exports (index.ts) par module |
API publique claire |
| Hooks personnalises pour la logique metier | Separation modele / vue |
7. Formatage et outillage¶
7.1 Configuration¶
| Outil | Role | Configuration |
|---|---|---|
| Prettier | Formatage automatique | 2 espaces, 100 colonnes, single quotes, trailing commas, semicolons, LF |
| ESLint | Analyse statique | Preset react-app + regles strictes TypeScript |
| TypeScript | Verification de types | strict: true, noUncheckedIndexedAccess: true |
7.2 Regles de formatage¶
- Indentation : 2 espaces (jamais de tabulations).
- Limite de colonnes : 100 caracteres.
- Guillemets : single quotes (
') pour les chaines, double quotes (") dans le JSX. - Points-virgules : obligatoires.
- Virgules finales : obligatoires (trailing commas).
- Fin de ligne : LF (Unix).
7.3 Commandes¶
| Action | Commande |
|---|---|
| Formater le code | npm run format |
| Verifier le formatage | npm run format:check |
| Linter | npm run lint |
| Verifier les types | npm run typecheck |
8. Styles CSS¶
Le projet utilise des fichiers CSS purs organises par couche FSD avec des variables CSS comme source de verite.
| Fichier | Portee | Contenu |
|---|---|---|
shared/theme/variables.css |
Global (:root) |
Tokens : couleurs, espacements, polices |
shared/ui/styles.css |
Composants partages | .shared-button, .shared-card |
features/*/ui/*.css |
Par feature | Styles specifiques |
app/styles/global.css |
Layout global | Sidebar, header, contenu |
Regles : inline styles interdits, noms de classes en .feature-component ou .shared-component, tokens references via var(--token-name).
9. Tests¶
| Outil | Role |
|---|---|
| Vitest ou Jest | Tests unitaires |
| React Testing Library | Tests de composants |
| MSW | Mocking des appels API |
- Fichiers co-localises :
MyComponent.test.tsxa cote deMyComponent.tsx. - Noms descriptifs avec
describe/it. - Tester le comportement visible, pas les details d'implementation.
- Utiliser
screen.getByRole,screen.getByText,screen.getByLabelText.
describe('MemoryGrid', () => {
it('renders the correct number of blocks', () => {
render(<MemoryGrid blocks={mockBlocks} tierType="dram" />);
expect(screen.getAllByRole('cell')).toHaveLength(mockBlocks.length);
});
});
Chaque PR doit inclure des tests pour le code modifie. Aucune regression de couverture acceptee.
10. Commentaires¶
- En anglais, concis. Expliquer le pourquoi, pas le comment.
- Pas d'emojis, d'ASCII art ou de decorations.
- JSDoc encourage sur les fonctions et composants publics :
/** Converts a raw byte count to a human-readable GiB string. */
export function formatGiB(bytes: number): string {
return `${(bytes / (1024 ** 3)).toFixed(2)} GiB`;
}
11. Checklist avant commit¶
npm run format— formater le code.npm run lint— corriger les erreurs de lint.npm run typecheck— zero erreur TypeScript.npm test— tous les tests passent.- Verifier le sens des imports FSD (pas d'import lateral entre features).
- Verifier l'absence de
any,console.logetdefault exportde composant.