---
name: typescript-standards
description: Conventions TypeScript pour le projet. Use when "add types", "typescript", "interface", "type definition".
allowed-tools: Read, Grep, Glob
---

# TypeScript Standards

## Purpose
Définir les conventions TypeScript pour le monorepo consultant-manager.

## Principes Généraux

### Strictness
- Activer `strict: true` dans tsconfig.json
- Pas de `any` sauf justification documentée
- Préférer `unknown` à `any` si type inconnu
- Utiliser `as const` pour 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**: `is` prefix (`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/types` si 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 `as` dangereuses
- [ ] Dates typées correctement (Date vs string)
- [ ] `npm run build` passe sans erreurs TypeScript

## Ressources

- [TypeScript Handbook](https://www.typescriptlang.org/docs/handbook/intro.html)
- [Zod Documentation](https://zod.dev/)
- [Prisma Type Safety](https://www.prisma.io/docs/concepts/components/prisma-client/advanced-type-safety)
