🟢 ① tsconfig.json 완전 정복 | 🟢 ② 개발 환경 세팅 | 🟢 ③ 기본 타입 정복 | 🟢 ④ interface vs type | 🟢 ⑤ 함수 타입 선언 | 🟢 ⑥ 유니언 & 인터섹션 타입 | 🟢 ⑦ 타입 추론과 단언 | 🔵 ⑧ 타입 좁히기 (Narrowing)
🔎 타입 좁히기(Narrowing) - typeof, in, instanceof 완전 정리
타입스크립트에서 유니언 타입을 쓸 경우, 특정 타입에 따라 분기처리를 해야 합니다.
이때 사용하는 것이 타입 좁히기 (Narrowing)입니다. 대표적인 narrowing 도구는 다음 3가지입니다:
typeof
in
instanceof
① typeof – 기본 타입 구분에 사용
typeof
는 string, number, boolean 등 원시 타입 구분에 주로 사용됩니다.
function printValue(value: string | number) {
if (typeof value === 'string') {
console.log('문자열 길이:', value.length);
} else {
console.log('숫자 제곱:', value * value);
}
}
가능한 typeof 체크:
typeof value === 'string' | 'number' | 'boolean' | 'undefined' | 'object' | 'function'
② in – 객체 속성 여부로 타입 구분
객체의 특정 속성 존재 여부로 타입을 좁히는 방법입니다.
type Admin = {
name: string;
role: string;
};
type User = {
name: string;
point: number;
};
function handle(person: Admin | User) {
if ('role' in person) {
console.log('관리자:', person.role);
} else {
console.log('일반 유저:', person.point);
}
}
💡 in
은 객체 타입 구분 시 가장 많이 쓰이는 실전용 narrowing 도구입니다.
③ instanceof – 클래스 인스턴스 구분
클래스로 생성된 객체(new
키워드)를 판단할 때 instanceof
를 사용합니다. 해당 객체가 특정 클래스의 인스턴스인지 검사하는 연산자
// OOP 스타일
class Dog {
bark() {
console.log('멍멍');
}
}
class Cat {
meow() {
console.log('야옹');
}
}
function makeSound(animal: Dog | Cat) {
if (animal instanceof Dog) {
animal.bark();
} else {
animal.meow();
}
}
const pet = new Dog();
if (pet instanceof Dog) { // new 키워드로 만든 클래스 기반 객체에서 작동
pet.bark(); // ✅ 가능
}
instanceof
는 생성자 기반 타입 체크에 유용합니다. 하지만 함수형 프로그래밍에서는 덜 사용됩니다.
✅ instanceof는 생성자 기반에서 유용하지만, 함수형 프로그래밍에선 잘 안 쓰이는 이유는?
함수형 프로그래밍은 보통 다음과 같은 특징이 있어요:
- 클래스보다 함수와 객체 리터럴 중심
- new Class() 보다는 { key: value } 또는 factory() 함수 사용
- 상태를 가지는 인스턴스를 거의 만들지 않음
💡 그래서 함수형에서는 instanceof를 쓰려 해도 비교 대상이 클래스 인스턴스가 아닌 일반 객체이기 때문에 잘 작동하지 않아요.
🔨 예시 비교
// 함수형 스타일
function createDog() {
return { bark: () => console.log('멍멍') };
}
const dog = createDog();
if (dog instanceof createDog) {
// ❌ 작동안함: createDog은 생성자가 아님
}
👉 결론:
instanceof는 클래스 중심(OOP) 스타일에서 유용하고,
함수형(FP) 환경에서는 in, typeof, 또는 커스텀 타입 가드(is)를 사용하는 게 더 적절해요.
④ 커스텀 타입 가드 (is)
직접 타입을 구분하는 함수를 만들 수도 있어요. 유니언 타입의 공통 속성이 없을 경우
type Fish = { swim: () => void };
type Bird = { fly: () => void };
function isFish(pet: Fish | Bird): pet is Fish { // 인자가 유니언 타입일 때, B타입이면
return (pet as Fish).swim !== undefined; // swim속성이 정의되어 있어!. typeScript에게 pet이 확실히 Fish라고 알려주는 증명서
}
function move(pet: Fish | Bird) {
if (isFish(pet)) {
pet.swim(); // ✅ Fish로 좁혀짐
} else {
pet.fly();
}
}
//타입체크를 하지 않는 경우
function move(pet: Fish | Bird) { // 매개변수는 아무거나 들어올 수 있는 경우 공통된 속성만 호출 가능함.
pet.swim(); // ❌ 에러. pet이 Bird일 수도 있으니까 typeScript는 판별할 수 없음
}
pet is Fish
처럼 직접 타입을 판별해주는 **사용자 정의 타입 가드 함수**도 강력한 도구입니다.
예시: 에러 응답 판별
type Success = { status: 'ok'; data: string };
type Fail = { status: 'error'; message: string };
function isSuccess(res: Success | Fail): res is Success {
return res.status === 'ok';
}
function handle(res: Success | Fail) {
if (isSuccess(res)) {
console.log(res.data); // ✅ Success로 타입 좁혀짐
} else {
console.log(res.message); // ✅ Fail로 추론됨
}
}
📐 요약
도구 | 용도 | 사용 예시 |
---|---|---|
typeof |
기본 타입 구분 | typeof x === 'string' |
in |
속성 존재 여부 | 'role' in person |
instanceof |
클래스 인스턴스 구분 | x instanceof MyClass |
is 타입 가드 |
사용자 정의 narrowing | pet is Fish |
📘 다음 글 예고
👉 제네릭(Generic)의 이해와 사용법 – 다양한 타입을 유연하게 다루는 핵심 개념을 배워봅니다.
'language > typescript' 카테고리의 다른 글
🔧 유틸리티 타입 – Partial, Pick, Omit 등 실무 핵심 정리 (0) | 2025.04.27 |
---|---|
📦 제네릭(Generic)의 이해와 사용법 (0) | 2025.04.27 |
🧠 타입 추론과 단언 – as, !, ??, ??= 완전 정리 (0) | 2025.04.27 |
🔀 유니언 타입 vs 인터섹션 타입 – | 와 &의 차이점 완벽 정리 (0) | 2025.04.27 |
🔧 함수의 타입 선언 – 매개변수, 반환, 옵셔널, 디폴트 완전 정복 (0) | 2025.04.27 |
댓글