피드로 돌아가기
Dev.toBackend
원문 읽기
Talliofi가 TypeScript Branded Types를 12줄의 코드로 구현해 928개의 금융 데이터 접근점을 보호하고 97개 파일에서 정수 센트 단위 변환 버그 제거
How a Branded Cents Type Eliminated an Entire Class of Bugs Across 97 Files
AI 요약
Context
JavaScript의 IEEE 754 부동소수점 연산으로 인해 0.1 + 0.2 = 0.30000000000000004 같은 오차가 발생하며, 이는 금융 애플리케이션에서 누적되어 사용자 신뢰도를 훼손한다. 금융 데이터를 정수 센트로 저장하는 방식이 수학적 오차는 해결하지만, 개발자가 달러 단위 number를 센트 단위로 잘못 전달하는 100배 스케일 버그를 예방할 수 없다.
Technical Solution
- Branded Type 정의:
type Cents = number & { readonly __brand: 'Cents' }교집합 타입으로 컴파일 타임에 Cents를 number와 구별되는 독립 타입으로 취급 - 검증 게이트 함수 구현:
cents()생성자 함수에서Number.isSafeInteger()검사로 유효한 정수 센트만 생성, 부동소수점·NaN·Infinity·안전 범위 초과값은 런타임 에러 발생 - 산술 연산 래퍼 작성: 단순
+연산 대신addCents(),subtractCents()같은 함수 구현으로 연산 결과도 Cents 타입 유지 - 마이그레이션 전략: 97개 파일의 기존 number 타입 금융값을 체계적으로 cents() 생성자를 거쳐 Cents 타입으로 변환
- Readonly 속성 결합: 도메인 타입 전체에 readonly 필드 적용해 생성 후 변경 불가능하게 강제
Impact
928개의 금융 데이터 접근점이 Branded Type으로 보호됨. 97개 파일에서 정수·부동소수점 혼용 버그가 완전히 제거됨. 마이그레이션 소요 시간은 1주일(약 168시간).
Key Takeaway
TypeScript Branded Type은 런타임 오버헤드 없이 컴파일 타임 타입 체크로 암묵적 의미를 가진 number 값의 오용을 원천 차단하는 패턴이며, 금전·백분율·타임스탬프·거리·ID 등 도메인별 암묵 정의가 있는 모든 숫자 데이터에 일반화 가능하다.
실천 포인트
금융 데이터를 다루는 TypeScript 프로젝트에서 Branded Type의 cents() 생성자 함수를 초기 커밋부터 도입하면, 개발 진행 시점에는 마이그레이션 비용이 미미하지만 97개 파일 규모에서는 1주일의 추가 작업을 요구하므로, 프로젝트 초기 단계에서 도입할수록 누적 수정 비용을 선형적으로 절감할 수 있다.