Skip to main content

Guide des Bonnes Pratiques de Développement TypeScript

🎯 Principes Généraux

⚠️ Intégrer les pratiques Angular dans le document.

Code de Qualité

  • Ne JAMAIS pousser du code qui ne compile pas
  • TOUJOURS tester localement avant commit
  • Suivre les patterns existants du projet
  • Respecter l'architecture Clean Architecture établie

Responsabilités

  • Un commit = une fonctionnalité/fix
  • Code review obligatoire pour les PR vers master
  • Documentation des changements d'API
  • Tests pour les nouvelles fonctionnalités

📝 Standards de Code TypeScript

Conventions de Nommage

TypeScript/JavaScript

// Classes et interfaces : PascalCase
export class UserService { }
export interface IUserConfiguration { }

// Méthodes et variables : camelCase
const getCurrentUser = async (userId: number) => { }
const userConfiguration: IUserConfiguration = { };

// Constantes : SCREAMING_SNAKE_CASE
const API_BASE_URL = 'http://localhost:5000';

Commentaires et Documentation

Commentaires TypeScript

/**
* Service pour gérer les configurations de modèles LLM côté client
* @example
* ```typescript
* const service = new ModelConfigurationService();
* const configs = await service.getUserConfigurations(userId);
* ```
*/
export class ModelConfigurationService {
/**
* Récupère les configurations d'un utilisateur
* @param userId - ID de l'utilisateur
* @returns Promise contenant la liste des configurations
*/
async getUserConfigurations(userId: number): Promise<ModelConfiguration[]> {
// Appel API avec gestion d'erreur
try {
const response = await this.httpClient.get(`/api/model-configurations/user/${userId}`);
return response.data;
} catch (error) {
// Log de l'erreur pour debug
console.error('Failed to fetch user configurations:', error);
throw new Error('Unable to load configurations');
}
}
}

🧪 Tests

Tests TypeScript avec Vitest

// ✅ CORRECT - Test de service TypeScript
import { describe, test, expect, vi, beforeEach } from 'vitest';
import { UserService } from '@/services/UserService';
import { ApiClient } from '@/services/ApiClient';

// Mock du client API
vi.mock('@/services/ApiClient');

describe('UserService', () => {
let userService: UserService;
let mockApiClient: vi.Mocked<ApiClient>;

beforeEach(() => {
mockApiClient = vi.mocked(new ApiClient());
userService = new UserService(mockApiClient);
vi.clearAllMocks();
});

test('getUserConfigurations récupère les configurations utilisateur', async () => {
// Arrange
const userId = 1;
const mockConfigurations = [
{ id: 1, name: 'Config 1', userId },
{ id: 2, name: 'Config 2', userId }
];
mockApiClient.get.mockResolvedValue({ data: mockConfigurations });

// Act
const result = await userService.getUserConfigurations(userId);

// Assert
expect(result).toEqual(mockConfigurations);
expect(mockApiClient.get).toHaveBeenCalledWith(`/api/users/${userId}/configurations`);
});

test('getUserConfigurations gère les erreurs API', async () => {
// Arrange
const userId = 1;
mockApiClient.get.mockRejectedValue(new Error('API Error'));

// Act & Assert
await expect(userService.getUserConfigurations(userId))
.rejects
.toThrow('Unable to load configurations');
});
});

Tests d'Intégration API

// ✅ CORRECT - Test d'intégration avec MSW
import { rest } from 'msw';
import { setupServer } from 'msw/node';
import { describe, test, expect, beforeAll, afterEach, afterAll } from 'vitest';
import { ApiClient } from '@/services/ApiClient';

// Mock du serveur API
const server = setupServer(
rest.get('/api/users/:userId/configurations', (req, res, ctx) => {
const { userId } = req.params;
return res(
ctx.status(200),
ctx.json([
{ id: 1, name: 'Test Config', userId: Number(userId) }
])
);
})
);

beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());

describe('ApiClient Integration', () => {
test('récupère les configurations utilisateur via API réelle', async () => {
// Arrange
const apiClient = new ApiClient('http://localhost:3000');

// Act
const response = await apiClient.get('/api/users/1/configurations');

// Assert
expect(response.data).toEqual([
{ id: 1, name: 'Test Config', userId: 1 }
]);
});
});

📖 Documentation

Documentation de Services TypeScript

/**
* UserService - Service pour gérer les utilisateurs et leurs configurations
*
* @example
* ```typescript
* const userService = new UserService(apiClient);
* const configs = await userService.getUserConfigurations(userId);
* ```
*/
export class UserService {
constructor(private apiClient: ApiClient) {}

/**
* Récupère les configurations d'un utilisateur
* @param userId - ID de l'utilisateur
* @returns Promise contenant la liste des configurations
* @throws {Error} Si l'utilisateur n'existe pas ou en cas d'erreur API
*/
async getUserConfigurations(userId: number): Promise<ModelConfiguration[]> {
try {
const response = await this.apiClient.get(`/api/users/${userId}/configurations`);
return response.data;
} catch (error) {
throw new Error('Unable to load configurations');
}
}
}

Documentation d'API avec TypeDoc

/**
* Interface pour la configuration d'un modèle LLM
* @interface ModelConfiguration
*/
export interface ModelConfiguration {
/** Identifiant unique de la configuration */
id: number;
/** Nom de la configuration */
name: string;
/** Nom de l'éditeur du modèle (ex: OpenAI, Google) */
editorName: string;
/** Nom du modèle (ex: gpt-4, gemini-pro) */
modelName: string;
/** Clé API pour accéder au modèle */
apiKey: string;
/** Prompt système optionnel */
systemPrompt?: string;
/** Date de création */
createdAt: Date;
/** Configuration active ou non */
isActive: boolean;
}

🆘 Aide et Ressources

Outils et Extensions Recommandés

  • VS Code: TypeScript Hero, Auto Import, Better Comments
  • Chrome Extensions: JSON Formatter, Postman Interceptor
  • Testing: Vitest, Testing Library, MSW
  • Linting: ESLint, Prettier, Husky

Ce guide est un document vivant. N'hésitez pas à proposer des améliorations via Pull Request.