Sua Blog
Type Guard
타입 가드(Type Guard)를 사용하면 조건문을 통해 타입을 좁혀 나갈 수 있다.
unknown
unknown 타입은 any 타입과 동일하게 모든 값을 허용하지만, 할당된 값이 어떤 타입인지 모르게 때문에 함부로 프로퍼티나 연산을 할 수 없다.
unknown 타입으로 변수를 정의하면 컴파일러에게 변수의 타입이 unknown이라 어떤 값이든 올 수 있으니 엄격하게 검사해라라고 요청하는 것과 동일하다.
unknown 타입의 변수를 사용할 때는 타입 가드를 해야하고 문제되는 코드를 미리 예방할 수 있다.
const whatType = (value: unknown): string => {
if (typeof value === 'string') {
return 'string';
} else if (typeof value === 'number') {
return 'number';
} else if (typeof value === 'boolean') {
return 'boolean';
} else if (typeof value === 'object') {
return 'object';
} else if (typeof value === 'function') {
return 'function';
}
return 'undefined';
};
typeof
TypeScript는 JavaScript의 instanceof, typeof 연산자를 이해할 수 있다. 즉 조건문에 typeof와 instanceof를 사용하면, TypeScript는 해당 조건문 블록 내에서는 해당 변수의 타입이 다르다는 것(=좁혀진 범위의 타입)으로 이해한다.
typeof type guard에서 타입 하나를 리턴할 경우 해당 타입으로는 더이상 추론되지 않는다.
const getNumber = (value: number | string): number => {
if (typeof value === 'number') {
return value;
}
return -1;
};
in
in은 객체 내부에 특정 property가 존재하는지를 확인하는 연산자로 type guard로 활용할 수 있다.
interface Admin {
id: string;
role: string;
}
interface User {
id: string;
email: string;
}
const redirect = (user: Admin | User) => {
if ('role' in User) {
console.log('Admin'); // Admin
} else {
console.log('User'); // User
}
};
리터럴
리터럴 타입은 동등(==), 일치(===)연산자 또는 switch로 타입 가드를 할 수 있다.
type TriState = 'yes' | 'no' | 'unknown';
const logOutState = (state: TriState) => {
if (state === 'yes') {
console.log('사용자가 yes를 골랐습니다.');
} else if (state === 'no') {
console.log('사용자가 no를 골랐습니다.');
} else {
console.log('사용자가 아직 결정을 내리지 않았습니다.');
}
};
union 타입에 리터럴이 있는 경우에도 공통 property 값을 비교해 구분할 수 있다.
type Drink = {
kind: 'drink', // 리터럴 타입
drink: string,
};
type Food = {
kind: 'food', // 리터럴 타입
food: string,
};
const somethingEat = (arg: Drink | Food) => {
if (arg.kind === 'drink') {
console.log(arg.drink); // 성공
console.log(arg.food); // 에러 발생
} else {
console.log(arg.drink); // 에러 발생
console.log(arg.food); // 성공
}
};
null과 undefined (strictNullCheks)
const foo = (a: number | null) => {
if (a === null) return;
// 이제부터 a는 무조건 number이다.
};
Custom Type Guard
사용자 정의 타입 가드는 단순히 어떤 인자명은 어떠한 타입이다라는 값을 리턴하는 함수다.
type Car = {
type: 'CAR';
wheel: number;
};
type Boat = {
type: 'BOAT';
motor: number;
};
const getWhellOrMotor = (machine: any): number => {
if (isCar(machine)) {
return machine.wheel; // machine은 Car
} else if (isBoat(machine)) {
return machine.motor; // machine은 Boat
} else {
return -1;
}
};
const isCar = (arg: any): arg is Car => {
return arg.type === 'CAR';
};
const isBoat = (arg: any): arg is Boat => {
return arg.type === 'BOAT';
};
is keyword를 사용하면 isCar 함수가 true를 반환하면 Typescript는 형식을 Car로 좁힌다.
유형 술어 https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards
참고
https://radlohead.gitbook.io/typescript-deep-dive/type-system/typeguard