6 min de lecture - Guide court du nommage des composants TypeScript : Angular et NestJS
Frontend & Backend Development
De bonnes conventions de nommage s'apparentent à une API bien conçue — elles rendent votre code auto-documenté et réduisent la charge cognitive de chaque développeur qui touche à votre base de code. Dans les applications TypeScript, en particulier dans les frameworks d'entreprise comme Angular et NestJS, un nommage cohérent devient encore plus critique à mesure que votre application grandit.
Après avoir travaillé sur des dizaines de projets Angular et NestJS, nous avons pu constater à quel point de mauvaises décisions de nommage s'accumulent avec le temps, ce qui crée de la confusion et ralentit le développement. À l'inverse, les équipes qui établissent des conventions de nommage claires dès le premier jour avancent plus vite, intègrent plus facilement les nouveaux développeurs et maintiennent une meilleure qualité de code.
Ce que vous allez apprendre
- Les conventions de nommage TypeScript fondamentales pour les classes, interfaces, méthodes et propriétés
- Les schémas de nommage spécifiques à Angular pour les composants, services, directives et pipes
- Les schémas de nommage NestJS pour les contrôleurs, services, repositories et DTO
- Des stratégies avancées pour les génériques, événements et callbacks
- Comment faire respecter ces conventions grâce à ESLint et des checklists de revue de code
Référence rapide
Utilisez le PascalCase pour les classes et interfaces, le camelCase pour les méthodes et propriétés, et le kebab-case pour les noms de fichiers. Les composants Angular ajoutent le suffixe
Component, les services le suffixeService. Les contrôleurs NestJS portent le nom de la ressource qu'ils gèrent, et les DTO indiquent leur direction (Create,Update,Response). Faites respecter ces conventions avec les règles@typescript-eslint/naming-convention.
Les bases : les conventions de nommage TypeScript
Le système de types de TypeScript nous offre des outils puissants pour créer du code auto-documenté, à condition de les utiliser de manière cohérente.
Classes et interfaces
Les classes doivent utiliser le PascalCase et décrire ce qu'elles représentent :
// Good
class UserService {}
class PaymentController {}
class DatabaseConnectionManager {}
// Avoid
class userservice {}
class paymentCtrl {}
class DBConnMgr {}
Les interfaces doivent également utiliser le PascalCase, avec un nom descriptif qui indique le contrat :
// Good
interface User {
id: string
email: string
}
interface PaymentGateway {
processPayment(amount: number): Promise<PaymentResult>
}
// Avoid - Hungarian notation is outdated
interface IUser {}
interface IPaymentGateway {}
Méthodes et propriétés
Utilisez le camelCase pour les méthodes et propriétés, avec des noms qui indiquent clairement leur objectif :
// Good
class UserService {
async findUserById(id: string): Promise<User> {}
async updateUserProfile(userId: string, data: UpdateUserDto): Promise<User> {}
private validateEmailFormat(email: string): boolean {}
}
// Avoid
class UserService {
async getUser(id: string) {} // Too generic
async upd(id: string, d: any) {} // Abbreviated and unclear
}
Schémas de nommage des composants Angular
L'architecture d'Angular fournit des directives précises pour nommer les différents types de composants et de services. Suivre ces conventions rend votre application plus maintenable et aide les autres développeurs Angular à comprendre immédiatement la structure de votre code. Nous avons appliqué ces principes de façon extensive lors de la conception de notre design system SoarUI et sur des applications Angular à grande échelle.
Classes de composants et fichiers
Les composants Angular doivent utiliser le PascalCase pour le nom de la classe et le kebab-case pour les noms de fichiers :
// file: user-profile.component.ts
@Component({
selector: 'app-user-profile',
templateUrl: './user-profile.component.html',
})
export class UserProfileComponent {
// Component logic
}
// file: payment-history-card.component.ts
@Component({
selector: 'app-payment-history-card',
templateUrl: './payment-history-card.component.html',
})
export class PaymentHistoryCardComponent {
// Component logic
}
Services et providers
Les services doivent porter des noms descriptifs qui indiquent leur responsabilité :
// Good - Clear responsibility
@Injectable()
export class UserAuthenticationService {
login(credentials: LoginCredentials): Observable<AuthResult> {}
logout(): void {}
refreshToken(): Observable<string> {}
}
@Injectable()
export class PaymentProcessingService {
processPayment(request: PaymentRequest): Observable<PaymentResult> {}
validateCard(cardNumber: string): boolean {}
}
// Avoid - Too generic
@Injectable()
export class DataService {}
@Injectable()
export class UtilService {}
Directives et pipes
Les directives et pipes personnalisés doivent porter des noms clairs et orientés action :
// Directive - describes what it does
@Directive({
selector: '[appHighlightOnHover]',
})
export class HighlightOnHoverDirective {}
// Pipe - describes the transformation
@Pipe({ name: 'formatCurrency' })
export class FormatCurrencyPipe {
transform(value: number, currency: string): string {}
}
Nommage des modules et services NestJS
NestJS suit des conventions similaires, mais possède ses propres schémas architecturaux qui influencent les décisions de nommage.
Contrôleurs
Les contrôleurs doivent être nommés d'après la ressource qu'ils gèrent, avec un mapping clair des méthodes HTTP :
// Good
@Controller('users')
export class UsersController {
@Get(':id')
async findUserById(@Param('id') id: string): Promise<UserResponseDto> {}
@Post()
async createUser(@Body() createUserDto: CreateUserDto): Promise<UserResponseDto> {}
@Put(':id/profile')
async updateUserProfile(
@Param('id') id: string,
@Body() updateProfileDto: UpdateProfileDto
): Promise<UserResponseDto> {}
}
// Avoid
@Controller('api/v1/user-management-endpoints')
export class UserMgmtCtrl {}
Services et repositories
Les services doivent porter des noms qui indiquent clairement leur domaine métier :
// Good - Domain-specific services
@Injectable()
export class UserAccountService {
async createAccount(userData: CreateAccountDto): Promise<User> {}
async deactivateAccount(userId: string): Promise<void> {}
}
@Injectable()
export class PaymentBillingService {
async calculateMonthlyBill(userId: string): Promise<BillingAmount> {}
async processRecurringPayment(subscriptionId: string): Promise<PaymentResult> {}
}
// Repository pattern
@Injectable()
export class UserRepository {
async findById(id: string): Promise<User | null> {}
async save(user: User): Promise<User> {}
async deleteById(id: string): Promise<void> {}
}
DTO et classes d'entités
Les Data Transfer Objects et les classes d'entités doivent clairement indiquer leur objectif :
// Good - Clear purpose and direction
export class CreateUserDto {
email: string
password: string
firstName: string
lastName: string
}
export class UserResponseDto {
id: string
email: string
firstName: string
lastName: string
createdAt: Date
// Note: password is never included in response DTOs
}
export class UpdateUserProfileDto {
firstName?: string
lastName?: string
phoneNumber?: string
}
// Entity
@Entity('users')
export class User {
@PrimaryGeneratedColumn('uuid')
id: string
@Column({ unique: true })
email: string
@Column()
hashedPassword: string
}
Stratégies de nommage avancées
Paramètres de type génériques
Utilisez des noms significatifs pour les paramètres de type génériques, en particulier dans les scénarios complexes :
// Good - Descriptive generic names
interface Repository<TEntity, TKey> {
findById(id: TKey): Promise<TEntity | null>
save(entity: TEntity): Promise<TEntity>
}
interface ApiResponse<TData, TError = ApiError> {
data?: TData
error?: TError
timestamp: Date
}
// Single letter for simple cases
interface List<T> {
items: T[]
length: number
}
Nommage des événements et callbacks
Utilisez des schémas cohérents pour les événements et les callbacks :
// Angular - Event emitters
@Component({})
export class UserProfileComponent {
@Output() userUpdated = new EventEmitter<User>()
@Output() profileDeleted = new EventEmitter<string>() // userId
onSaveProfile(): void {
// Handle save logic
this.userUpdated.emit(this.user)
}
}
// NestJS - Event handlers
@Injectable()
export class UserEventHandler {
@OnEvent('user.registered')
handleUserRegistered(payload: UserRegisteredEvent): void {}
@OnEvent('payment.processed')
handlePaymentProcessed(payload: PaymentProcessedEvent): void {}
}
Conventions d'équipe et outillage
Établir des standards d'équipe
Documentez vos conventions de nommage dans un guide de style qui couvre :
- Les schémas de nommage des fichiers et dossiers
- Les règles de nommage des classes, interfaces et méthodes
- Les schémas spécifiques à votre domaine (par exemple, services financiers, e-commerce)
- Les directives d'abréviation et les acronymes approuvés
Application automatisée
Utilisez des règles ESLint pour faire respecter les conventions de nommage :
// .eslintrc.json
{
"rules": {
"@typescript-eslint/naming-convention": [
"error",
{
"selector": "class",
"format": ["PascalCase"]
},
{
"selector": "interface",
"format": ["PascalCase"]
},
{
"selector": "method",
"format": ["camelCase"]
},
{
"selector": "property",
"format": ["camelCase"]
}
]
}
}
Checklist de revue de code
Intégrez des vérifications de convention de nommage dans votre processus de revue de code :
- Les noms de classes et d'interfaces sont-ils descriptifs et suivent-ils le PascalCase ?
- Les noms de méthodes indiquent-ils clairement leur action et suivent-ils le camelCase ?
- Les DTO sont-ils correctement nommés selon leur direction (Create, Update, Response) ?
- Les noms de fichiers correspondent-ils aux noms de classes et suivent-ils les conventions du framework ?
Des noms au service de votre équipe
Des conventions de nommage cohérentes portent leurs fruits avec le temps. Les nouveaux membres de l'équipe s'intègrent plus rapidement, les bugs liés à une mauvaise compréhension des responsabilités des composants diminuent, et les IDE offrent un meilleur support d'autocomplétion et de refactoring. L'investissement consenti pour établir ces schémas dès le départ se rentabilise plusieurs fois à mesure que l'application grandit.
Le code est lu bien plus souvent qu'il n'est écrit. Choisissez des noms qui auront du sens pour vous-même et vos coéquipiers dans six mois. Si vous avez besoin d'aide pour établir ces conventions au sein d'une base de code en pleine croissance, nous pouvons vous accompagner.
Vous développez avec Angular ?
Des bibliothèques de composants aux produits complets, nous avons déployé Angular à grande échelle sur des dizaines de projets.