보통 객체 데이터는 Id 값을 가진다.
그리고 때때로 각 데이터는 특정 Id값이나 카테고리에서 좀 다른 데이터 패턴을 보일 때가 있다.
또는, 하나의 객체에서 여러 Id값을 지닐때 같은 number 타입의 Id긴 하지만 굳이 따지면 다른 데이터값이기는 하는... 이런 경우도 종종 있다.
이런 경우 타입을 짜는게 참으로 곤란한데, 이때 __brand 라는 걸 사용해서 더 구체적으로 타입을 구별하는 기법을 사용한다고 한다 👻
+ 객체가 아닌 타입에도 intersection을 통해서 객체로 __brand 타입을 집어넣어 같은 number지만 같지 않은 그런 타이핑이 가능하다 !
요약하자면, 좀 더 엄격하게 객체들의 타입을 구분할때 고려할 수 있는 방법이다.
(+ 런타임에서는 영향이 없고, 컴파일 타임에서만 타입을 구별할 수 있게 할 수 있다)
__brand란? 🍲
타입스크립트는 구조적 타이핑을 한다. 따라서, 객체의 형태가 같으면 같은 타입으로 판단한다.
이 때문에 의도치 않은 타입 호환 문제가 발생할 수 있는데...
예를 들어, UserId와 ProductId가 모두 number 타입인 경우, UserId를 기대하는 함수에 ProductId를 전달해도 타입 에러가 발생하지 않는다.
type UserId = number;
type ProductId = number;
function getUser(id: UserId) {
// ...
}
const productId: ProductId = 123;
getUser(productId); // 오류 없음!
이런 경우에 __brand를 사용하여 타입을 구별할 수 있다.
__brand 사용법
__brand는 심볼(Symbol) 또는 문자열(String)을 사용하여 타입에 고유한 태그를 추가하는 방식이다.
- 심볼 사용하기
const userIdSymbol = Symbol('userId');
const productIdSymbol = Symbol('productId');
type UserId = number & { [userIdSymbol]: true };
type ProductId = number & { [productIdSymbol]: true };
function getUser(id: UserId) {
// ...
}
function getProduct(id: ProductId) {
// ...
}
function createUserId(id: number): UserId {
return id as UserId;
}
function createProductId(id: number): ProductId {
return id as ProductId;
}
const userId = createUserId(123);
const productId = createProductId(456);
getUser(userId); // 정상
getUser(productId); // 오류!
getProduct(productId); // 정상
getProduct(userId); // 오류!
- 문자열 사용하기
type UserId = number & { __brand: 'UserId' };
type ProductId = number & { __brand: 'ProductId' };
function getUser(id: UserId) {
// ...
}
function getProduct(id: ProductId) {
// ...
}
function createUserId(id: number): UserId {
return id as UserId;
}
function createProductId(id: number): ProductId {
return id as ProductId;
}
const userId = createUserId(123);
const productId = createProductId(456);
getUser(userId); // 정상
getUser(productId); // 오류!
getProduct(productId); // 정상
getProduct(userId); // 오류!
__brand를 사용하면 좋은 점 😁
- 타입 안정성
같은 형태의 타입이라도 목적에 따라 구분하여 사용할 수 있다 - 가독성
코드의 의도를 명확하게 표현할 수 있다 - 유지보수성
타입 에러를 컴파일 타임에 발견하여 런타임 오류를 줄일 수 있다
주의사항 🫘
- __brand는 런타임에 영향을 주지 않으므로, 런타임 검사를 수행하지 않는다.
- __brand는 타입스크립트의 타입 시스템을 활용하는 테크닉이므로, 타입스크립트를 사용하지 않는 환경에서는 사용할 수 없다 (사실 당연한 이야기이지만...)
🌠 참고 자료
https://www.youtube.com/watch?v=Zsj1UlCsuio
https://toss.tech/article/typescript-type-compatibility
TypeScript 타입 시스템 뜯어보기: 타입 호환성
타입호환성은 무엇이며 왜 필요할까요? 타입호환이 지원되지 않는 경우가 존재한다는 것을 아셨나요? 평소 익숙했던 개념들에 대해 질문을 던져가며 TypeScript 타입 시스템에 관해 심도있게 알아
toss.tech
'TypeScript' 카테고리의 다른 글
TypeScript에서 객체 타입 비교 및 extends 활용하기 🏘️ (0) | 2025.03.21 |
---|---|
[typescript] Record를 사용하여 객체 Key 타입 설정하기 🍎 (0) | 2024.11.01 |
타입스크립트에서 기존 코드로부터 타입을 가져오는 법 ReturnType, ComponentProps (0) | 2024.09.18 |
타입가드 사용하여 안전하게 타입스크립트 타이핑하기 (0) | 2024.08.04 |
TypeScript에서 enum 사용하기: const enum vs as const 객체 (0) | 2024.04.01 |