TypeScript 4.3의 override 키워드와 안전한 상속 구조

문제 상황

레거시 코드를 리팩토링하던 중 BaseService 클래스의 메서드명이 initialize에서 init으로 변경되었는데, 이를 상속받은 20여개의 서비스 클래스에서 오버라이드한 메서드들이 제대로 호출되지 않는 버그가 발생했다. 메서드명 변경 사실을 몰랐던 것이 원인이었다.

class BaseService {
  init() { // initialize에서 변경됨
    console.log('base init');
  }
}

class UserService extends BaseService {
  initialize() { // 오타인지 의도인지 알 수 없음
    console.log('user init');
  }
}

TypeScript 4.3의 override 키워드

5월에 릴리즈된 TypeScript 4.3에서 추가된 override 키워드가 이 문제를 해결해준다. --noImplicitOverride 플래그를 활성화하면 상속 메서드를 오버라이드할 때 명시적으로 키워드를 붙여야 한다.

class UserService extends BaseService {
  override init() { // 부모 클래스에 실제로 존재하는지 검증
    console.log('user init');
  }
  
  override initialize() { // Error: 부모에 없는 메서드
    console.log('user init');
  }
}

적용 결과

tsconfig.json에 옵션을 추가하고 기존 코드에 override 키워드를 붙이는 작업을 진행했다. 예상대로 여러 곳에서 오버라이드하지 못한 메서드들이 발견되었고, 런타임에서야 발견되었을 버그들을 사전에 제거할 수 있었다.

{
  "compilerOptions": {
    "noImplicitOverride": true
  }
}

클래스 기반 아키텍처를 사용하는 프로젝트라면 충분히 도입 가치가 있는 기능이다. 다만 기존 코드베이스가 크다면 마이그레이션 비용을 고려해야 한다.

TypeScript 4.3의 override 키워드와 안전한 상속 구조