Organisation des Fichiers TypeScript
Structure des fichiers
Conventions de nommage des fichiers
- kebab-case pour les noms de fichiers
- Extensions explicites (
.ts,.tsx,.d.ts) - Suffixes descriptifs pour le type de fichier
// ✅ Bonnes pratiques
user-service.ts // Service
user.model.ts // Modèle/interface
user.types.ts // Types uniquement
user.test.ts // Tests
user.spec.ts // Spécifications
user.config.ts // Configuration
user.constants.ts // Constantes
index.ts // Point d'entrée
// ❌ À éviter
UserService.ts // PascalCase pour fichiers
user_service.ts // snake_case
userservice.ts // Pas de séparation
user.js // Extension JavaScript
Organisation du contenu des fichiers
- Imports en haut du fichier
- Déclarations de types et interfaces
- Constantes et variables
- Classes et fonctions
- Export en fin de fichier
// ✅ Structure recommandée pour un fichier TypeScript
// 1. Imports des bibliothèques externes
import express from 'express';
import { Request, Response } from 'express';
import jwt from 'jsonwebtoken';
// 2. Imports des modules internes (ordre alphabétique)
import { DatabaseService } from './database.service';
import { Logger } from './logger.service';
import { UserRepository } from './repositories/user.repository';
// 3. Imports des types
import type { User, CreateUserRequest } from './types/user.types';
import type { ApiResponse } from './types/api.types';
// 4. Constantes et configuration
const DEFAULT_TOKEN_EXPIRY = '24h';
const MAX_LOGIN_ATTEMPTS = 5;
// 5. Types et interfaces locaux
interface AuthenticationResult {
success: boolean;
token?: string;
user?: User;
error?: string;
}
// 6. Implémentation des classes et fonctions
export class AuthService {
constructor(
private readonly userRepository: UserRepository,
private readonly databaseService: DatabaseService,
private readonly logger: Logger
) {}
async authenticate(credentials: LoginCredentials): Promise<AuthenticationResult> {
// Implémentation
}
}
// 7. Fonctions utilitaires
function hashPassword(password: string): Promise<string> {
// Implémentation
}
function generateToken(user: User): string {
// Implémentation
}
// 8. Exports par défaut (si nécessaire)
export default AuthService;
Modules et imports
Types d'imports
- Imports nommés pour la plupart des cas
- Imports d'espace de noms pour les grandes APIs
- Éviter les imports par défaut sauf cas spécifique
// ✅ Imports nommés (préférable)
import { Component, OnInit, Input } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Router } from '@angular/router';
// ✅ Import d'espace de noms pour les grandes APIs
import * as fs from 'fs';
import * as path from 'path';
import * as express from 'express';
// ✅ Import de type uniquement
import type { User } from './types/user';
import type { ApiResponse } from './types/api';
// ✅ Import par défaut quand justifié
import React from 'react';
import express from 'express';
// ❌ Éviter les imports mixtes confus
import React, { Component, useState } from 'react'; // Préférer tout nommé
// ✅ Mieux
import * as React from 'react';
const { Component, useState } = React;
Organisation des imports
- Grouper les imports par origine
- Ordre alphabétique dans chaque groupe
- Ligne vide entre les groupes
// Groupe 1: Bibliothèques Node.js natives
import fs from 'fs';
import path from 'path';
// Groupe 2: Bibliothèques tierces
import express from 'express';
import { Request, Response } from 'express';
import lodash from 'lodash';
// Groupe 3: Modules internes (chemins relatifs)
import { ConfigService } from '../config/config.service';
import { DatabaseService } from '../database/database.service';
import { LoggerService } from './logger.service';
// Groupe 4: Types uniquement
import type { AppConfig } from '../config/types';
import type { DatabaseConnection } from '../database/types';
Exports structurés
// ✅ Exports nommés organisés
// user.service.ts
export class UserService {
// Implementation
}
export class UserValidator {
// Implementation
}
export const USER_CONSTANTS = {
MIN_AGE: 18,
MAX_NAME_LENGTH: 50
} as const;
export type { User, CreateUserRequest } from './user.types';
// ✅ Re-exports pour créer des points d'entrée
// index.ts
export { UserService, UserValidator, USER_CONSTANTS } from './user.service';
export { UserRepository } from './user.repository';
export type { User, CreateUserRequest, UpdateUserRequest } from './user.types';
// ✅ Export par défaut pour les modules principaux
// app.ts
class Application {
// Implementation
}
export default Application;
Fichiers de déclaration
Fichiers .d.ts
- Types et interfaces partagés
- Déclarations de modules externes
- Augmentation de types existants
// types/global.d.ts
declare global {
interface Window {
APP_CONFIG: AppConfig;
analytics: AnalyticsClient;
}
namespace NodeJS {
interface ProcessEnv {
NODE_ENV: 'development' | 'production' | 'test';
DATABASE_URL: string;
JWT_SECRET: string;
}
}
}
// types/express.d.ts
declare module 'express-serve-static-core' {
interface Request {
user?: User;
correlationId: string;
}
}
// types/modules.d.ts
declare module '*.json' {
const value: any;
export default value;
}
declare module '*.css' {
const content: { [className: string]: string };
export default content;
}
Fichiers de types métier
// types/user.types.ts
export interface User {
readonly id: string;
readonly email: string;
firstName: string;
lastName: string;
role: UserRole;
createdAt: Date;
updatedAt: Date;
}
export interface CreateUserRequest {
email: string;
firstName: string;
lastName: string;
password: string;
role?: UserRole;
}
export interface UpdateUserRequest {
firstName?: string;
lastName?: string;
role?: UserRole;
}
export type UserRole = 'admin' | 'user' | 'guest';
export type UserStatus = 'active' | 'inactive' | 'suspended';
// Types utilitaires
export type UserPublicData = Omit<User, 'password' | 'email'>;
export type UserPermissions = Record<string, boolean>;
Structure de projet
Architecture modulaire
src/
├── types/ # Types globaux
│ ├── global.d.ts
│ ├── api.types.ts
│ └── index.ts
├── config/ # Configuration
│ ├── database.config.ts
│ ├── app.config.ts
│ └── index.ts
├── services/ # Services métier
│ ├── user.service.ts
│ ├── auth.service.ts
│ └── index.ts
├── repositories/ # Accès aux données
│ ├── base.repository.ts
│ ├── user.repository.ts
│ └── index.ts
├── controllers/ # Contrôleurs HTTP
│ ├── user.controller.ts
│ ├── auth.controller.ts
│ └── index.ts
├── middleware/ # Middlewares
│ ├── auth.middleware.ts
│ ├── error.middleware.ts
│ └── index.ts
├── utils/ # Utilitaires
│ ├── logger.util.ts
│ ├── validation.util.ts
│ └── index.ts
├── models/ # Modèles de données
│ ├── user.model.ts
│ ├── order.model.ts
│ └── index.ts
└── app.ts # Point d'entrée
Fichiers index.ts pour les re-exports
// services/index.ts
export { UserService } from './user.service';
export { AuthService } from './auth.service';
export { EmailService } from './email.service';
// repositories/index.ts
export { UserRepository } from './user.repository';
export { OrderRepository } from './order.repository';
// types/index.ts
export type { User, CreateUserRequest } from './user.types';
export type { Order, CreateOrderRequest } from './order.types';
export type { ApiResponse, PaginatedResponse } from './api.types';
// Utilisation simplifiée
import { UserService, AuthService } from './services';
import { UserRepository } from './repositories';
import type { User, ApiResponse } from './types';
Chemins d'import
Configuration des chemins absolus
// tsconfig.json
{
"compilerOptions": {
"baseUrl": "./src",
"paths": {
"@/*": ["*"],
"@/types/*": ["types/*"],
"@/services/*": ["services/*"],
"@/utils/*": ["utils/*"],
"@/config/*": ["config/*"]
}
}
}
// ✅ Avec chemins absolus configurés
import { UserService } from '@/services/user.service';
import { Logger } from '@/utils/logger.util';
import type { User } from '@/types/user.types';
import { DATABASE_CONFIG } from '@/config/database.config';
// ❌ Sans configuration (chemins relatifs complexes)
import { UserService } from '../../../services/user.service';
import { Logger } from '../../utils/logger.util';
Bonnes pratiques pour les imports
// ✅ Chemins courts et clairs
import { UserService } from '@/services';
import type { User } from '@/types';
// ✅ Imports groupés par fonctionnalité
import {
UserService,
AuthService,
EmailService
} from '@/services';
// ✅ Types séparés des implémentations
import type { User, Order } from '@/types';
import { UserService, OrderService } from '@/services';
// ❌ Éviter les imports trop profonds
import { validateEmail } from '@/services/user/validators/email/email.validator';
// ✅ Préférer des points d'entrée
import { validateEmail } from '@/services/user/validators';
Fichiers de configuration
Configuration TypeScript
// tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"lib": ["ES2020"],
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "**/*.test.ts"]
}
Configuration ESLint pour TypeScript
// .eslintrc.json
{
"extends": [
"@typescript-eslint/recommended",
"@typescript-eslint/recommended-requiring-type-checking"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "./tsconfig.json"
},
"rules": {
"@typescript-eslint/explicit-function-return-type": "error",
"@typescript-eslint/no-explicit-any": "warn",
"@typescript-eslint/no-unused-vars": "error",
"@typescript-eslint/prefer-const": "error",
"import/order": [
"error",
{
"groups": [
"builtin",
"external",
"internal",
"parent",
"sibling",
"index"
],
"newlines-between": "always"
}
]
}
}
Bonnes pratiques
1. Séparation des responsabilités
// ✅ Un fichier = une responsabilité claire
// user.controller.ts - Gestion des requêtes HTTP
// user.service.ts - Logique métier
// user.repository.ts - Accès aux données
// user.types.ts - Types et interfaces
// user.test.ts - Tests unitaires
// ❌ Éviter les fichiers fourre-tout
// user.ts - Tout mélangé
2. Barrel exports pour l'organisation
// services/user/index.ts
export { UserService } from './user.service';
export { UserValidator } from './user.validator';
export { UserMapper } from './user.mapper';
// services/index.ts
export * from './user';
export * from './auth';
export * from './email';
// Utilisation propre
import { UserService, AuthService } from '@/services';
3. Éviter les dépendances circulaires
// ❌ Dépendance circulaire
// user.service.ts
import { OrderService } from './order.service';
// order.service.ts
import { UserService } from './user.service';
// ✅ Solution: extraire les types communs
// shared.types.ts
export interface User { /* ... */ }
export interface Order { /* ... */ }
// user.service.ts
import type { Order } from './shared.types';
// order.service.ts
import type { User } from './shared.types';
4. Documentation et commentaires
/**
* Service de gestion des utilisateurs
*
* @example
* ```typescript
* const userService = new UserService(userRepository);
* const user = await userService.createUser({
* email: '[email protected]',
* name: 'John Doe'
* });
* ```
*/
export class UserService {
/**
* Crée un nouvel utilisateur
*
* @param userData - Données de l'utilisateur à créer
* @returns Promise résolue avec l'utilisateur créé
* @throws {ValidationError} Si les données sont invalides
* @throws {ConflictError} Si l'email existe déjà
*/
async createUser(userData: CreateUserRequest): Promise<User> {
// Implementation
}
}