"매일 쓰지 않는 타입도, 필요한 순간 다른 타입으로 흉내 내면 계약이 무너져."
symbol: 충돌하지 않는 키
Symbol()을 호출할 때마다 다른 값이 만들어져. 같은 설명 문자열을 줘도 두 symbol은 서로 같지 않아. 이 고유성 덕분에 다른 코드와 이름이 겹치지 않는 객체 키, 프로토콜 표식, 메타데이터 키를 만들 수 있어.
JavaScript 표준도 Symbol.iterator, Symbol.asyncIterator 같은 잘 알려진 symbol을 사용해 객체가 특정 동작을 제공한다고 표시해. 문자열 이름으로 같은 일을 했다면 우연한 속성 충돌을 피하기 어려웠을 거야.
unique symbol과 타입 수준의 정체성
const TOKEN: unique symbol = Symbol()처럼 선언하면 그 상수 하나만의 고유 타입을 얻을 수 있어. 다른 symbol과 섞이지 않는 브랜드나 판별 키를 만들 때 유용해. 일반 symbol 타입이 ‘어떤 symbol이든’을 뜻한다면 unique symbol은 ‘바로 이 symbol 하나’를 뜻해.
객체 속성 키로 쓸 때는 대괄호 문법을 사용해. symbol 키는 일반적인 Object.keys 결과에 나오지 않으므로, 열거와 직렬화가 필요한 데이터에는 맞지 않아. 숨긴다는 말과 보안이라는 말도 구별해야 해. 찾기 어렵게 할 뿐 접근 권한을 막는 장치는 아니야.
bigint: 안전한 정수 범위 너머
JavaScript의 number는 부동소수점이라 Number.MAX_SAFE_INTEGER를 넘는 정수를 정확히 표현하지 못해. bigint는 크기에 사실상 제한이 없는 정수 타입이고, 숫자 뒤에 n을 붙여 9007199254740993n처럼 만든다.
number와 bigint는 암묵적으로 섞이지 않아. 1n + 1은 오류고, 어느 쪽으로 계산할지 명시적으로 변환해야 해. 이 엄격함은 정밀도를 실수로 잃는 일을 막아. 다만 JSON은 bigint를 기본으로 직렬화하지 못하므로 문자열 변환 같은 경계 정책이 필요해.
언제 손을 뻗을까
symbol은 라이브러리 프로토콜과 충돌 없는 내부 키에, bigint는 큰 정수의 정확성이 실제 요구인 곳에 써. 평범한 ID가 안전 범위 안에 있고 직렬화가 중요하다면 number나 string이 더 단순할 수 있어. 드문 도구를 쓴다는 사실보다 왜 다른 도구로는 계약을 지킬 수 없는지가 중요해.
원시 타입과 래퍼 객체를 구별해
타입 표기에는 소문자인 symbol과 bigint를 써. 대문자 Symbol과 BigInt는 래퍼 객체 쪽 이름이라 원시값 타입 표기로 쓰지 않아. string과 String, number와 Number의 관계와 같은 규칙이야.