타입스크립트 공식문서 :https://www.typescriptlang.org/docs/handbook/2/narrowing.html#discriminated-unions
Documentation - Narrowing
Understand how TypeScript uses JavaScript knowledge to reduce the amount of type syntax in your projects.
www.typescriptlang.org
서버에 api 요청을 보냈다.
요청이 별 문제 없이 성공할 경우 내가 원하는 데이터가 넘어올 것이고 요청이 실패한다면 넘어오지 않을 것이다.
이 때 에러처리를 위해서 요청이 실패할 경우, 각 경우에 맞는 에러객체를 만들어서 반환하도록 설계해보자.
그러면 이제 api 요청을 보냈을 때 넘겨 받을 수 있는 데이터는 2가지 중 하나이다.
1. 요청한 데이터 객체 (ApiMovie)
2. 에러 객체 (ApiError)
private async getApiData(){
const url = this.makeUrl();
const apiData = await request(url);
return apiData;
}
타입스크립트를 활용해 apiData가 데이터객체이거나 에러 객체이라는 것을 명시해주고 싶다.
둘 중 하나일테고 다른 데이터객체가 반환될수는 없으니까!
타입을 명시해준다면 데이터를 받아서 쓰는 쪽에서 프로퍼티를 안전하게 사용할 수 있는 장점을 활용하고 싶다.
private async getApiData():Promise< ApiMovie | ApiError >{
const url = this.makeUrl();
const apiData = await request(url);
return apiData;
}
오 좋은데?
그런데 반환타입을 명시해주자마자 데이터를 받아서 사용하는 메소드에 빨간 줄이 그어지기 시작했다.
async getMovies() {
const apiData = await this.getApiData();
if (apiData.error) {
console.log(`${apiData.errorMessage}로 인한 에러가 발생했습니다.`);
return;
}
const desiredData = apiData.results;
console.log(`원하던 데이터입니다.`);
}
apiData는 apiMovie이거나 apiError 인데
apiMovie에는 error 속성이 없고, apiError에는 results 속성이 없다고 타입스크립트가 불만을 표시하는 거다!
왜냐면 메소드 입장에서는 apiData가 apiMovie인지 apiError인지 알 수 없으니까.
Generic으로 해결해줘볼까?
//Generic 사용 해결 예시
private async getApiData<T>(): Promise<Awaited<T>> {
const url = this.makeUrl();
const apiData = await request(url);
return apiData;
}
에러는 없어졌지만 apiMovie와 apiError에 있는 속성을 보장받으면서 안전하게 사용하고 싶다.
Generic은 정말 아무 객체나 반환할 수 있는 거 잖아 ㅠㅠ
이 때 타입스크립트의 Discriminated Union이라는 스펙을 활용해보자.
반환받을 수 있는 두 개의 객체에 type(네이밍은 달라도 된다. 같은 네임이기만 하면 됨!)이라는 속성을 명시적으로 넣어주고 type의 값을 활용해 반환받은 객체가 두 가지 중 어떤 객체인지 확인 후 사용할 수 있게 하는 것이다.
interface ApiMovie {
page: number;
total_pages: number;
results: ApiMovieItem[];
total_results: number;
}
interface ApiError {
error: number;
errorMessage: string;
}
이런 식으로 존재하던 인터페이스를
interface ApiMovie {
type:'fulfilled';
page: number;
total_pages: number;
results: ApiMovieItem[];
total_results: number;
}
interface ApiError {
type:'rejected';
error: number;
errorMessage: string;
}
type 속성을 추가해줬다.
이제 데이터를 받아오는 쪽 메소드를 수정해주자.
async getMovies() {
const apiData = await this.getApiData();
if (apiData.type === 'rejected') {
console.log(`${apiData.errorMessage}로 인한 에러가 발생했습니다.`);
return;
}
const desiredData = apiData.results;
console.log(`원하던 데이터입니다.`);
}
type을 확인시킨 후 다뤄주니 더 이상 에러를 발생시키지 않는다! 얄루~~
객체 안에 있는 속성도 자동완성으로 떠서 안전하게 오타걱정이나 없는 속성을 불러올 걱정없이 사용할 수 있게 되었다!
'Study Output for Myself > TypeScript' 카테고리의 다른 글
[Typescript] Utility Types (0) | 2023.04.28 |
---|---|
[TS] Generic(제네릭) (0) | 2022.07.05 |
[TS]속성접근자 (0) | 2022.07.04 |
[TS]인터페이스(interface) (0) | 2022.07.02 |
[TS]타입 알리아스(type alias) (0) | 2022.07.02 |