Typescript 팁: 브랜드 유형을 사용하면 더 안전한 기능을 사용할 수 있습니다.

다음과 같은 함수가 있다고 상상해 보십시오.

interface Post {
  id: number
  title: string
}

export function getPosts(page: number): Post[] {
  // perform some query to return posts from a database
  // ...
  // ...
  return []
}

getPostspage 인수를 수락하고 데이터 소스에서 게시물을 검색합니다.

자, 만약 getPosts가 이렇게 사용된다면?

const posts = getPosts(-1);


페이지 번호는 음수가 될 수 없기 때문에 분명히 잘못된 것입니다. 간단한 해결책은 다음과 같은 줄을 추가하는 것입니다.

if(page < 0) throw Error('Page must be a positive number')`


그러나 음수로 함수를 호출하려고 할 때 유형 오류가 발생하면 좋지 않을까요?

여기서 문제는 유형number이 우리 기능에 너무 일반적이라는 것입니다. number는 임의의 숫자가 될 수 있으며 양수만 예상합니다.

이에 대한 유형 별칭을 만들 수 있습니다.

type PositiveNumber = number;


코드를 더 읽기 쉽게 만들지만 간단한 별칭을 사용한다고 해서 문제가 해결되지는 않습니다. 우리는 여전히 getPosts() 에 대한 인수로 임의의 숫자를 전달할 수 있기 때문입니다.

이때 Branded Type을 만들 수 있습니다.

브랜드 유형



기본 유형이 너무 일반적인 경우 이 패턴을 사용할 수 있습니다.

type PositiveNumber = number & { __type: 'PositiveNumber' };


여기서 우리는 기본 유형( number )과 __type 속성이 있는 객체 사이의 교차점을 사용하고 있습니다. 이 사유 속성은 브랜드 유형을 보유하고 일반 number 과 구별하는 데 사용됩니다.

함수를 다음과 같이 다시 작성할 수 있습니다.

type PositiveNumber = number & { __type: 'PositiveNumber' };

export function getPosts(page: PositiveNumber): Post[] {
  // ...
  return []
}


이제 이전처럼 호출하려고 하면 예상한 오류가 발생합니다.

const posts = getPosts(-1); 
// ^^^ Argument of type 'number' is not assignable to parameter of type 'PositiveNumber'.


유효한 숫자로 시도해 봅시다.

const posts = getPosts(2); 
// ^^^ Argument of type 'number' is not assignable to parameter of type 'PositiveNumber'.


흠, 말이 안 되는군요 🤔, 확실히 2는 양수입니다.

여전히 number 가 아니라 PositiveNumber 를 전달하고 있기 때문에 여전히 동일한 오류가 발생합니다. PositiveNumber 키워드를 사용하여 as를 전달한다고 컴파일러에 명시적으로 알려야 합니다.

const posts = getPosts(2 as PositiveNumber); 


그러면 오류가 제거됩니다.

이제 양수인지 아닌지 알 수 없는 변수가 있으면 어떻게 할까요?

const { page } = incomingRequest.body;  
// here, page could be a positive or a negative number, so we can't use the `as` keyword because we can't be sure of what is the actual value;

const posts = getPosts(page); 


이를 해결하기 위해 페이지가 실제라고 주장하는 주장 함수를 사용할 수 있습니다PositiveNumber.

function assertsPositiveNumber(value: number): asserts value is PositiveNumber {
  if(value < 0) throw new Error('Value must be a positive number');
}


이제 이 주장을 통해 page가 양수인지 아닌지 알 수 있습니다.

const { page } = incomingRequest.body;  

assertsPositiveNumber(page);

const posts = getPosts(page); // at this point TypeScript know that `page` its a PositiveNumber



이 팁이 마음에 드셨다면, 공유하고 ♥를 눌러주세요.

추가 자료:


  • Assertion Functions
  • Branding and Type-Tagging
  • 좋은 웹페이지 즐겨찾기