TypeScript Standards
Purpose
Définir les conventions TypeScript pour le monorepo consultant-manager.
Principes Généraux
Strictness
- •Activer
strict: truedans tsconfig.json - •Pas de
anysauf justification documentée - •Préférer
unknownàanysi type inconnu - •Utiliser
as constpour les littéraux immuables
Organisation des Types
Types Partagés (utilisés par backend ET frontend):
typescript
// shared/types.ts
export interface Consultant {
id: string;
nom: string;
prenom: string;
// ...
}
Types Backend Spécifiques:
typescript
// backend/src/types/index.ts
import { Consultant } from '@shared/types';
import { Prisma } from '@prisma/client';
Types Frontend Spécifiques:
typescript
// frontend/src/types/index.ts
import { Consultant } from '@shared/types';
export interface ConsultantFormData extends Omit<Consultant, 'id' | 'dateCreation'> {
// ...
}
Conventions de Nommage
Interfaces vs Types
typescript
// ✅ Interface pour objets et classes
interface Consultant {
id: string;
nom: string;
}
// ✅ Type pour unions, intersections, utilitaires
type ConsultantStatus = 'DISPONIBLE' | 'EN_MISSION' | 'EN_CONGES' | 'INDISPONIBLE';
type PartialConsultant = Partial<Consultant>;
Nommage
- •Interfaces/Types: PascalCase (
Consultant,MissionWithConsultant) - •Enums: PascalCase (
StatutConsultant) - •Type guards:
isprefix (isConsultant,hasActiveMission) - •Génériques: Lettres simples ou descriptif (
T,TData,TResponse)
Patterns Spécifiques au Projet
Backend: Request/Response Types
typescript
// Controllers avec types explicites
import { Request, Response } from 'express';
export const createConsultant = async (req: Request, res: Response) => {
const validatedData = consultantSchema.parse(req.body);
// ...
};
// Typer les paramètres de route
interface ConsultantParams {
id: string;
}
export const getConsultant = async (
req: Request<ConsultantParams>,
res: Response
) => {
const { id } = req.params;
// ...
};
Frontend: Props et States
typescript
// Props d'un composant
interface ConsultantFormProps {
consultant: Consultant | null;
onClose: () => void;
onSave?: (consultant: Consultant) => void;
}
export default function ConsultantForm({
consultant,
onClose,
onSave
}: ConsultantFormProps) {
// ...
}
// State hooks typés
const [consultants, setConsultants] = useState<Consultant[]>([]);
const [loading, setLoading] = useState<boolean>(false);
const [error, setError] = useState<string | null>(null);
Prisma Types
typescript
import { Consultant, Mission, Prisma } from '@prisma/client';
// Type généré incluant relations
type ConsultantWithMissions = Prisma.ConsultantGetPayload<{
include: { missions: true }
}>;
// Utiliser dans les fonctions
function calculateStatus(consultant: ConsultantWithMissions): string {
// ...
}
Utilitaires TypeScript
Types Utilitaires Courants
typescript
// Omit pour exclure des champs type ConsultantCreate = Omit<Consultant, 'id' | 'dateCreation' | 'dateModification'>; // Pick pour sélectionner des champs type ConsultantSummary = Pick<Consultant, 'id' | 'nom' | 'prenom' | 'statut'>; // Partial pour rendre tout optionnel type ConsultantUpdate = Partial<ConsultantCreate>; // Required pour rendre tout requis type ConsultantFull = Required<Consultant>;
Type Guards
typescript
// Vérifier qu'un objet est un Consultant
function isConsultant(obj: unknown): obj is Consultant {
return (
typeof obj === 'object' &&
obj !== null &&
'id' in obj &&
'nom' in obj &&
'prenom' in obj
);
}
// Utilisation
if (isConsultant(data)) {
console.log(data.nom); // TypeScript sait que data est Consultant
}
Zod et TypeScript
Inférer Types depuis Zod
typescript
import { z } from 'zod';
const consultantSchema = z.object({
nom: z.string().min(1),
prenom: z.string().min(1),
email: z.string().email(),
tjm: z.number().positive()
});
// Inférer le type depuis le schema
type ConsultantInput = z.infer<typeof consultantSchema>;
// Utiliser dans la fonction
function validateConsultant(data: unknown): ConsultantInput {
return consultantSchema.parse(data);
}
Date Handling
typescript
// Toujours typer les dates clairement
interface Mission {
dateDebut: Date; // Objet Date
dateFin: Date; // Objet Date
}
// Pour les API responses (JSON)
interface MissionResponse {
dateDebut: string; // ISO 8601 string
dateFin: string; // ISO 8601 string
}
// Conversion
function toMissionResponse(mission: Mission): MissionResponse {
return {
...mission,
dateDebut: mission.dateDebut.toISOString(),
dateFin: mission.dateFin.toISOString()
};
}
Erreurs Courantes à Éviter
❌ Mauvais: any partout
typescript
function processData(data: any): any {
return data.map((item: any) => item.value);
}
✅ Bon: Types explicites
typescript
function processData(data: Consultant[]): number[] {
return data.map(consultant => consultant.tjm);
}
❌ Mauvais: Types incomplets
typescript
interface Consultant {
nom: string;
// Oubli d'autres champs...
}
✅ Bon: Types complets alignés avec Prisma
typescript
interface Consultant {
id: string;
nom: string;
prenom: string;
email: string;
telephone: string | null;
competences: string[];
tjm: number;
statut: ConsultantStatus;
dateCreation: Date;
dateModification: Date;
}
❌ Mauvais: Assertions non sûres
typescript
const consultant = data as Consultant; // Dangereux!
✅ Bon: Validation avec Zod
typescript
const consultant = consultantSchema.parse(data); // Sûr, validé
Checklist TypeScript
Avant de commiter du code TypeScript:
- • Aucune utilisation de
any(ou justifiée et documentée) - • Types partagés dans
/shared/typessi utilisés par plusieurs workspaces - • Interfaces pour tous les objets métier (Consultant, Mission, etc.)
- • Props React typées
- • Request/Response typés côté backend
- • Validation Zod avec inférence de types
- • Pas d'assertions
asdangereuses - • Dates typées correctement (Date vs string)
- •
npm run buildpasse sans erreurs TypeScript