Frontend/Typescript

타입 가드(Type Guard): typeof, instanceof, is를 활용한 안전한 타입 좁히기

미니임 2026. 2. 19. 00:56

타입스크립트(TypeScript)에서 가장 중요한 개념 중 하나인 '타입 가드(Type Guard)'에 대한 블로그 게시글을 작성해 드립니다. 이 글은 typeof, instanceof, 그리고 사용자 정의 타입 가드인 is를 중심으로 풍부한 예제와 함께 구성되었습니다.

코드 스니펫
 
# 타입 가드(Type Guard): typeof, instanceof, is를 활용한 안전한 타입 좁히기

타입스크립트를 사용하다 보면 유니온 타입(Union Type)을 자주 접하게 됩니다. 여러 타입을 허용함으로써 유연성을 얻지만, 특정 타입에만 존재하는 속성이나 메서드에 접근하려고 할 때 컴파일러가 경고를 보냅니다. 이때 필요한 것이 바로 **'타입 좁히기(Type Narrowing)'**이며, 이를 가능하게 하는 도구가 **'타입 가드(Type Guard)'**입니다.

런타임 환경에서 값의 타입을 확인하고, 그 범위 안에서 안전하게 코드를 작성하는 방법을 알아보겠습니다.

---

## 1. typeof 연산자: 기본 타입 좁히기

`typeof`는 자바스크립트의 기본 연산자로, `string`, `number`, `boolean`, `symbol` 등 기본 자료형(Primitive type)을 구분할 때 가장 간편하게 사용됩니다.

### 예제: 단위 변환 함수
입력값이 숫자인지 문자열인지에 따라 다르게 처리하는 예제입니다.

```typescript
function formatPadding(value: string | number): string {
  // typeof를 사용하여 타입을 좁힙니다.
  if (typeof value === "number") {
    // 이 블록 안에서 value는 'number' 타입으로 추론됩니다.
    return `${value}px`;
  }
  
  // 이 블록 안에서 value는 자동으로 'string' 타입으로 추론됩니다.
  return value.trim();
}

console.log(formatPadding(20));      // "20px"
console.log(formatPadding(" 10rem ")); // "10rem"

주의사항: typeof는 null이나 배열을 object로 반환하기 때문에, 객체 내부 구조를 파악할 때는 적합하지 않습니다.


2. instanceof 연산자: 클래스 인스턴스 확인

instanceof는 생성자의 prototype 속성이 객체의 프로토타입 체인 어딘가에 존재하는지 확인합니다. 주로 클래스 기반의 객체 지향 프로그래밍에서 특정 클래스의 인스턴스인지 확인할 때 유용합니다.

예제: 알림 시스템

다양한 알림 클래스가 있을 때 각 클래스의 특화된 메서드를 호출하는 예제입니다.

TypeScript
 
class Email {
  sendEmail() {
    console.log("이메일을 발송합니다.");
  }
}

class SMS {
  sendSMS() {
    console.log("문자 메시지를 발송합니다.");
  }
}

function sendNotification(service: Email | SMS) {
  if (service instanceof Email) {
    // service가 Email 클래스의 인스턴스임이 보장됩니다.
    service.sendEmail();
  } else {
    // service는 SMS 타입으로 좁혀집니다.
    service.sendSMS();
  }
}

sendNotification(new Email());

3. 사용자 정의 타입 가드: is 키워드

인터페이스(Interface)는 런타임에 존재하지 않습니다. 따라서 typeof나 instanceof로는 인터페이스 타입을 구분할 수 없습니다. 이때 사용하는 것이 **타입 술어(Type Predicate)**인 is를 활용한 사용자 정의 함수입니다.

함수의 반환 타입을 variable is Type 형태로 정의하면, 해당 함수가 true를 반환할 때 타입스크립트는 그 변수를 해당 타입으로 간주합니다.

예제: API 응답 처리

성공과 실패 응답이 서로 다른 인터페이스를 가질 때의 처리 방식입니다.

TypeScript
 
interface SuccessResponse {
  status: 'success';
  data: string[];
}

interface ErrorResponse {
  status: 'error';
  message: string;
}

// 사용자 정의 타입 가드 함수
function isSuccessResponse(response: SuccessResponse | ErrorResponse): response is SuccessResponse {
  return response.status === 'success';
}

function processResponse(response: SuccessResponse | ErrorResponse) {
  if (isSuccessResponse(response)) {
    // 이 안에서 response는 SuccessResponse 타입입니다.
    console.log("데이터 개수:", response.data.length);
  } else {
    // 이 안에서 response는 자동으로 ErrorResponse 타입이 됩니다.
    console.error("에러 메시지:", response.message);
  }
}

4. 복합적인 예제: 데이터 필터링

실무에서는 배열 내의 유효하지 않은 값(null, undefined)을 제거하고 타입을 정제할 때 타입 가드를 자주 활용합니다.

TypeScript
 
function isNotNull<T>(value: T | null | undefined): value is T {
  return value !== null && value !== undefined;
}

const mixedValues: (string | null)[] = ["Apple", null, "Banana", null, "Cherry"];

// 타입 가드를 적용하지 않으면 string[] 타입으로 할당할 수 없습니다.
const validFruits: string[] = mixedValues.filter(isNotNull);

console.log(validFruits); // ["Apple", "Banana", "Cherry"]

요약

안전한 타입스크립트 코드를 작성하기 위해 상황에 맞는 타입 가드를 선택하세요.

  1. typeof: 문자열, 숫자 등 기본 자료형을 확인할 때.
  2. instanceof: 클래스로 생성된 객체를 구분할 때.
  3. is (사용자 정의): 인터페이스나 복합적인 로직으로 타입을 좁혀야 할 때.

타입 가드를 적절히 활용하면 불필요한 타입 단언(as)을 줄일 수 있으며, 런타임 에러를 방지하고 가독성 높은 코드를 완성할 수 있습니다.

타입 가드의 개념부터 실무에서 활용하기 좋은 예제들까지 포함하여 게시글을 작성했습니다. 도움 되시길 바랍니다. 추가적으로 궁금한 점이나 수정이 필요한 부분이 있다면 알려주세요.

반응형