안녕하세요 웹 YB 박희선입니다 😃
저는 현재 웹부스 스터디에 참여 중인데요, 바로 지난주 공부 범위에 타입 가드가 포함되어 있었습니다. 그때는 실제 프로젝트를 진행하면서 "자주 사용을 할까?"라는 의문이 들었었죠. 그런데 이번 과제를 진행하면서 실제로 타입 가드를 사용하게 되었고, 그 과정에서 타입 가드가 전용 문법이 있는 것이 아니라, 흔히 쓰는 제어문(예: if 문 등)을 활용해서도 오류를 최소화할 수 있다는 점을 알게 되었습니다.
그래서 이번 4주차 공유과제 주제로 타입 가드를 선택하게 되었습니다.
일반적으로 타입 가드에서 사용되는 키워드
1. typeof: 일반 타입 체킹
2. instanceof: 클래스 체킹
3. Array.isArray(): 배열 체킹
4. .type / in: 객체 속성 체킹
사실 위의 키워드들은 어떤 특별한 문법이 아니라, 모두 자바스크립트 코드인데요, 자바스크립트는 타입이 유연하기 때문에 타입 체킹 키워드들을 사용할 일이 없지만, 앞으로는 정말 많이 보게되실 아이들입니다.... !!!
일반 타입 가드 typeof
function numOrStr(a: number | string) {
a.toFixed(1);
}
위와 같은 코드처럼, 아무 생각 없이 작성했다가 에러가 뜨는 상황이 아주 빈번하게 발생하는데요, 타입스크립트 입장에서 toFixed는 number 전용 메소드인데 a가 number도 string도 될 수 있으니 에러가 날 것을 대비해 빨간줄로 우리에게 경고를 해주겠죠??
" string | number " 형식에 'toFixed' 속성이 없습니다. 'string' 형식에 'toFixed' 속성이 없습니다 " .. .. .. 아아 .. . . ..
🥹 하지만 간단하게 typeof 키워드를 사용해서 조건 분기만 잘 해주면 해결할 수 있습니다.
function numOrStr(a: number | string) {
if (typeof a === 'string') {
a.split(',');
}
if (typeof a === 'number') {
a.toFixed(1);
}
}
앞으로 타입스크립트를 다룰 때마다 union 타입을 만나는 상황이 굉장히 많은데, 이때 타입 가드로 방어를 해주는 것이 중요합니다.
내장 클래스 타입을 보장할 수 있는 타입가드 instanceof
function func(value: number | string | Date | null) {
if (typeof value === "number") {
console.log(value.toFixed());
} else if (typeof value === "string") {
console.log(value.toUpperCase());
} else if (value instanceof Date) {
console.log(value.getTime());
}
}
Date는 날짜 등을 포함하는 내장 클랙스 인데요, instanceof는 내장 클래스 또는 직접 만든 클래스에만 사용이 가능합니다. 따라서 우리가 직접 만든 타입과 함께 사용할 수 없습니다.
우리가 직접 만든 타입과 함께 사용할 수 있는 in
type Person = {
name: string;
age: number;
};
function func(value: number | string | Date | null | Person) {
if (typeof value === "number") {
console.log(value.toFixed());
} else if (typeof value === "string") {
console.log(value.toUpperCase());
} else if (value instanceof Date) {
console.log(value.getTime());
} else if (value && "age" in value) {
console.log(`${value.name}은 ${value.age}살 입니다`)
}
}
age 문자가 객체에 key 속성으로서 쓰임을 검사하면 타입 가드를 할 수 있습니다.
이번 과제를 진행하면서 실제로 사용했던 부분을 가져와봤습니다.
const loginData: PostLoginRequest = {
username,
password,
};
const response = await signIn(loginData);
로그인 함수(signIn)에 아이디와 비밀번호 값을 보내고 그에 대한 응답을 받습니다. 4주차 과제 문서에 있는 서버 명세서를 보면, 로그인에 대한 response 값은 다음과 같이 설정되어 있습니다.
response (success)
{
"result" : {
"token" : "abc"
}
}
response (failed)
{
"code" : "00"
}
if ('result' in response) {
localStorage.setItem('accessToken', response.result.token);
console.log('로그인 요청결과:', response); // 요청 결과 콘솔로 출력
... ...
..
}
if ('result' in response)는 response 객체가 result라는 속성을 가지고 있는지 확인하는 조건문입니다. 만약 response 객체에 result 속성이 존재하면, TypeScript는 이 시점에서 response 객체가 result 속성을 가졌다고 판단하고, 안전하게 접근할 수 있습니다.
위에서 타입 가드는 어떠한 문법이 아니라, 여러 방법으로 나올 수 있는 타입을 좁혀주는 모든 것이라고 말씀드렸는데요, 다음과 같은 것들도 타입 가드로써 활용된 에시입니다.
비교구문
비교 조건과 그의 반대 조건을 합하면 모든 케이스를 커버합니다.
type Person = {
play: () => void;
sing: () => void;
talk: () => void;
};
function playWithPerson(person: Person | undefined) {
if (!person) {
// person은 undefined로 추론됨.
throw new Error('Person not found!');
}
// person은 Person으로 추론됨.
person.play();
}
function talkWithPerson(person: Person | undefined | null) {
if (!person) {
// person은 undefined | null로 추론됨.
throw new Error('Person not found!');
}
// person은 Person으로 추론됨.
person.talk();
}
동등 연산자
function doSomething(left: string | number, right: string | boolean) {
if (left === right) {
// left와 right가 모두 string으로 추론됨.
console.log(left.toLowerCase());
console.log(right.toLowerCase());
return;
}
// left는 string | number, right는 string | boolean으로 추론됨.
console.log(`${left}`);
console.log(`${right}`);
}
인터페이스 타입가드
인터페이스를 타입가드 하는 기법은 객체 타입 가드와 같습니다.
인터페이스에 식별할 수 있는 타입 속성을 기재해주고 .type 으로 검사해주면 됩니다!
interface Person {
type: 'a';
name: string;
age: number;
}
interface Product {
type: 'b';
name: string;
price: number;
}
function print(value: Person | Product) {
if (value.type === 'a') {
console.log(value.age);
} else {
console.log(value.price);
}
}
번외: 할당
할당 구문도 아래 케이스처럼 일종의 타입가드로 사용하는 것입니다!
let value: string | number;
value = 3;
// value는 number로 추론됨.
value.toFixed(5);
value = 'abc';
// value는 string으로 추론됨.
value.split('').reverse().join('');
(참고문서
https://www.typescriptlang.org/docs/handbook/2/narrowing.html
https://ts.winterlood.com/92c2035a-49bc-4585-9e3d-43206ce92d59)
'4주차' 카테고리의 다른 글
프로젝트 초기 세팅하는 법 (0) | 2024.11.13 |
---|---|
리액트 useParams 와 Query String (0) | 2024.11.13 |
💥 로딩/에러처리 및 데이터 패칭 라이브러리 (0) | 2024.11.12 |
한 번 설정해두면 개발이 편해지는,,, Axios Interceptor (0) | 2024.11.12 |
[React] 타입 단언은 대체 (0) | 2024.11.12 |