본문 바로가기
Web/TypeScript

TypeScript Assertion - 특정 타입을 확신할 수 있는 경우

by 김첨지 2024. 6. 18.

 
타입스크립트를 사용하다보면 아래와 같은 상황을 자주 볼 수 있다.

 

const foo = useQueryParams("foo")  //  {title: string} | undefined

return (
  <div> {foo.title} </div>  // Error: undefined일 수 있음
)

 
그리고 다음 방법 중 하나를 사용하곤 한다.
 

const foo = useQueryParams("foo")  //  {title: string} | undefined

/* 1. Early Return 사용 */
if (!foo) {  
  return null
}

/* 2. Optional Chaining 사용 */
return (
  <div> {foo?.title} </div>  
)

 
하지만 사용하는 페이지에서 무조건 foo가 있다는 것을 확신할 수 있다면 (없으면 페이지 진입 자체가 안되는 경우)
 
더 좋은 방법이 있지 않을까?
 

Assert signature

 
타입스크립트에 assert signature라는 것이 있다.

 

function assert(condition: any, msg?: string): asserts condition {
  if (!condition) {
    throw new Error(msg)
  }
}

const foo = useQueryParams("foo")

assert(!foo, foo가 없습니다)

return (
  <div> {foo.title} </div>
)


asserts는 함수에서 에러가 발생하지 않으면, conditon이 참임을 타입스크립트에 알려준다.
 
따라서 foo.title이 undefined가 아님을 알려주고, {title: string} 타입으로 narrowing된다. 
 

응용

 
파라미터의 타입을 확인하지 않고, 타입스크립트에 특정 타입을 알려줄 수 있다.

 

function assertIsString(val: any): asserts val is string {
  if (typeof val !== "string") {
    throw new Error("Not a string!");
  }
}

 
assertIsString 함수에서 에러가 발생하지 않으면, 타입스크립트는 val의 타입을 string로 내로잉한다.
 

function test(str: any) {
  assertIsString(str);
  // 타입스크립트는 'str'이 'string'임을 알고 있다.
  
  return str.toUppercase();
  //         ~~~~~~~~~~~
  // error: Property 'toUppercase' does not exist on type 'string'.
  //        Did you mean 'toUpperCase'?
}

 
이는 is에서 사용했던 방식과 매우 유사하다

 

 

Reference

 
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#assertion-functions