Our offices

  • Exceev Consulting
    61 Rue de Lyon
    75012, Paris, France
  • Exceev Technology
    332 Bd Brahim Roudani
    20330, Casablanca, Morocco

Follow us

4 min read - A Short Guide to TypeScript Component Naming: Angular and NestJS Best Practices

Frontend & Backend Development

Good naming conventions are like a well-designed API—they make your code self-documenting and reduce cognitive load for every developer who touches your codebase. In TypeScript applications, especially in enterprise frameworks like Angular and NestJS, consistent naming becomes even more critical as your application scales.

After working on dozens of Angular and NestJS projects, I've seen how poor naming decisions compound over time, creating confusion and slowing down development. Conversely, teams that establish clear naming conventions from day one move faster, onboard new developers more easily, and maintain higher code quality.

The Foundation: TypeScript Naming Conventions

TypeScript's type system gives us powerful tools for creating self-documenting code, but only if we use them consistently. Here are the core principles that apply across both Angular and NestJS:

Classes and Interfaces

Classes should use PascalCase and describe what they represent:

// ✅ Good
class UserService {}
class PaymentController {}
class DatabaseConnectionManager {}

// ❌ Avoid
class userservice {}
class paymentCtrl {}
class DBConnMgr {}

Interfaces should also use PascalCase, with a descriptive name that indicates the contract:

// ✅ Good
interface User {
  id: string
  email: string
}

interface PaymentGateway {
  processPayment(amount: number): Promise<PaymentResult>
}

// ❌ Avoid - Hungarian notation is outdated
interface IUser {}
interface IPaymentGateway {}

Methods and Properties

Use camelCase for methods and properties, with names that clearly indicate their purpose:

// ✅ 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
}

Angular Component Naming Patterns

Angular's architecture provides specific guidance for naming different types of components and services. Following these conventions makes your application more maintainable and helps other Angular developers understand your code structure immediately.

Component Classes and Files

Angular components should use PascalCase for the class name and kebab-case for file names:

// 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 and Providers

Services should have descriptive names that indicate their responsibility:

// ✅ 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 and Pipes

Custom directives and pipes should have clear, action-oriented names:

// 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 {}
}

NestJS Module and Service Naming

NestJS follows similar conventions but has its own architectural patterns that influence naming decisions.

Controllers

Controllers should be named after the resource they manage, with clear HTTP method mappings:

// ✅ 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 and Repositories

Services should have names that clearly indicate their business domain:

// ✅ 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> {}
}

DTOs and Entity Classes

Data Transfer Objects and Entity classes should clearly indicate their purpose:

// ✅ 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
}

Advanced Naming Strategies

Generic Type Parameters

Use meaningful names for generic type parameters, especially in complex scenarios:

// ✅ 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
}

Event and Callback Naming

Use consistent patterns for events and 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 {}
}

Team Conventions and Tooling

Establishing Team Standards

Document your naming conventions in a style guide that covers:

  • File and folder naming patterns
  • Class, interface, and method naming rules
  • Specific patterns for your domain (e.g., financial services, e-commerce)
  • Abbreviation guidelines and approved acronyms

Automated Enforcement

Use ESLint rules to enforce naming conventions:

// .eslintrc.json
{
  "rules": {
    "@typescript-eslint/naming-convention": [
      "error",
      {
        "selector": "class",
        "format": ["PascalCase"]
      },
      {
        "selector": "interface",
        "format": ["PascalCase"]
      },
      {
        "selector": "method",
        "format": ["camelCase"]
      },
      {
        "selector": "property",
        "format": ["camelCase"]
      }
    ]
  }
}

Code Review Checklist

Include naming convention checks in your code review process:

  • Are class and interface names descriptive and follow PascalCase?
  • Do method names clearly indicate their action and follow camelCase?
  • Are DTOs properly named with their direction (Create, Update, Response)?
  • Do file names match the class names and follow framework conventions?

The Long-Term Benefits

Consistent naming conventions pay dividends over time:

Faster Onboarding: New team members can understand code structure immediately Reduced Bugs: Clear names reduce misunderstandings about component responsibilities
Better Tooling: IDEs can provide better autocomplete and refactoring support Easier Maintenance: Future developers (including yourself) can navigate the codebase efficiently

At Exceev, we've seen how proper naming conventions can dramatically improve development velocity and code quality in large TypeScript applications. The investment in establishing these patterns early in a project pays for itself many times over as the application grows.

Remember: code is read far more often than it's written. Choose names that will make sense to your future self and your teammates six months from now.

More articles

Emerging Fund Managers Are Challenging VC Orthodoxy: Why the "Shrinking Manager" Narrative Is Dead Wrong

While headlines claim emerging managers are disappearing, savvy investors are launching specialized funds with unique advantages. Discover how new VCs are outperforming established firms and reshaping startup investment.

Read more

The Future of AI is Smaller, Faster, and Everywhere: Why On-Device LLMs Are a Game-Changer

The era of massive, cloud-tethered AI is making way for a new revolution: powerful, efficient Large Language Models that live right on your devices. Discover how this shift is redefining privacy, performance, and the very fabric of application development.

Read more

Tell us about your project

Our offices

  • Exceev Consulting
    61 Rue de Lyon
    75012, Paris, France
  • Exceev Technology
    332 Bd Brahim Roudani
    20330, Casablanca, Morocco