TL;DR


is 키워드


타입스크립트에서 타입 범위를 좁혀나가는 작업(기능)을 타입가드라고 부른다. 간단한 타입은 in typeof 키워드 등을 사용할 수 있지만 ➊타입이 복잡하거나 ➋타입 체크 로직을 재사용하고 싶을 땐 사용자 정의 타입 가드 함수를 만들어서 사용한다. 타입 가드 함수는 리턴문에 is 키워드를 이용해서 “어떤 인자는 어떤 타입이다” 라는 값(타입 명제/술부; Predicate)을 리턴하는 함수라고 볼 수 있다.

<aside> <img src="/icons/search_gray.svg" alt="/icons/search_gray.svg" width="40px" /> 술부(Predicate; 谓词)란? 주어의 상태, 성질 따위를 서술하는 말(참고)!.innerHTML%3B-,%ED%83%80%EC%9E%85%20%EA%B0%80%EB%93%9C(Guards),-%EB%8B%A4%EC%9D%8C%20%EC%98%88%EC%A0%9C%EC%99%80%20%EA%B0%99%EC%9D%B4). value is Type 형태는 술부보단 명제(고래는 포유류다 처럼 참/거짓을 판단할 수 있는 내용)가 더 어울리는 단어인 것 같다

</aside>

아래 logPersonAge 함수는 Person Product 두가지 타입의 인자를 받는다. 타입스크립트는 어떤 타입의 값을 인자로 받을지 모르기 때문에 타입가드 없이 value.age 값을 사용하면 ts(2339) 에러가 발생한다.

interface Person { name: string; age: number; }
interface Product { name: string; price: number; }

// 타입 가드 함수는 주로 isTypeName 형태의 함수명을 사용한다
// is 키워드는 parameterName is Type 형태로 사용한다
function isPerson(value: Person | Product): value is Person {
	return (value as Person).age !== undefined; // true | false
}

function logPersonAge(value: Person | Product) {
	console.log(value.age) // Error! Property 'age' does not exist on type 'Product'
	if (isPerson(value)) console.log(value.age);
	else console.log('value does not have age properties');
}

logPersonAge({ name: 'smith', age: 30 }) // 30
logPersonAge({ name: 'iPhone', price: 600 }); // value does not have age properties

<aside> <img src="/icons/search_gray.svg" alt="/icons/search_gray.svg" width="40px" /> isPerson 함수 리턴 타입에 명시한 value is Person 구문이 타입 명제(술부)다

</aside>

이처럼 is 키워드를 사용해서 boolean 값을 반환하는 함수를 type predicates(타입 명제)라고 부른다. 즉, 반환 타입이 타입 명제인 함수는 예외를 발생시키지 않고 단순히 boolean 값을 반환한다. 반환한 boolean 값이 참이라면 함수를 호출한 스코프내에서 해당 명제(value is Type)의 타입 정보가 적용된다.

아래는 입력받은 파라미터가 number 타입인지 확인하는 isNumber 타입가드 예시. Array.at() 메서드는 인자에 명시한 인덱스의 요소를 반환하는데, 요소가 존재하지 않을 수도 있기 때문에 요소타입 | undefined 유니온 타입을 갖는다. 요소 타입을 확인할 때 lastEl !== undefined 같은 조건문 대신 isNumber 타입 가드를 적용하면 undefined 타입 뿐만 아니라 실제로 number 타입인지도 확인할 수 있는 장점이 있다.

// 타입 가드 정의
const isNumber = (value: unknown): value is number => {
  return typeof value === 'number' && !isNaN(value); // true or false 반환
};

const arr = [1, 2, 3];
const lastEl = arr.at(-1); // number | undefined

// 타입 가드를 사용하여 number 타입인지 확인
if (isNumber(lastEl)) {
  console.log("Last element is a number:", lastEl);
} else {
  console.log("Last element is not a number or is undefined");
}

asserts 키워드


asserts is 키워드를 함께 사용해서 잠재적인 예외를 발생(throw)시키고, void를 리턴하는 함수(리턴값이 없는 함수)는 assertion functions라고 부른다. assertion 함수가 예외를 발생시키지 않는다면 리턴값의 명제(value is Type)는 참이 되고, 함수를 호출한 스코프내에서 명제의 타입 정보가 적용된다.