기존의 javascript로 구현된 레거시 프로젝트에 typescript를 입히는 과정에서 겪은 상황과 해결방법을 정리한 포스팅입니다.
서버에 데이터 요청시 공통으로 사용하는 파라미터의 타입들을 정해준다.
주로 리스트의 데이터를 가져오는 API 호출을 많이 사용해서 Request에 paging 관련 정보를 넣는다.
export interface CommonRequest {
pagingNo: number;
pagingSize: number;
pagingSort: string;
}
서버에서 공통으로 응답되는 것과 상황별 응답 데이터를 구분한다.
서버에서 응답값을 줄 때 공통적으로 주는 부분을 정의한다.
export interface CommonResponse {
resultCd: string;
errCd: string;
errMsg: string;
// 아래 데이터는 필수값이 아니므로 ? 사용
pagingLastPageNo?: number;
pagingNo?: number;
pagingRowCnt?: number;
pagingTotCnt?: number;
}
실제 API를 호출하는 상황에서 응답 받을 데이터를 정의한다.
예를 들어 장바구니 아이템 리스트를 가져오고 싶다면, 장바구니 아이템 자체에 대해 먼저 타입을 정의한다.
export interface Item {
name: string;
price: number;
type: string;
createDate: string;
}
실제 데이터는 장바구니 아이템이 여러개 담긴 배열 형태로 떨어진다.
export interface ItemListResponse extends CommonResponse {
list: Item[]
}
extends를 활용해 공통으로 사용하는 응답 타입들을 사용하고, list라는 변수의 타입을 먼저 정의한 Item 객체 배열로 정의한다.
axios 라이브러리를 통해 공통으로 API 호출을 정의하는 로직을 정의한다.
import axios, { AxiosInstance, AxiosResponse } from 'axios';
import { CommonRequest } from '@/modules/types/api/common';
// axios instance 생성
const customAxios: AxiosInstance = axios.create({
headers: {
access_token: `${accessToken}`
}
});
// 실제 API 통신
// path : API url
// params : request parameter
export const doAxios = async <T>(path: string, params: CommonRequest): Promise<T | null> => {
try {
const { status, data }: AxiosResponse<T> = await customAxios.post(path, params);
return status < 500 ? data : null
} catch (err) {
console.log(err)
}
};
제네릭을 이용해서 위 메소드를 호출하는 시점에 타입을 넘겨줄 수 있도록 한다. 이렇게 하면 doAxios 로 반환되는 값은 특정 타입을 갖게 된다.
import { useCallback } from 'react';
import { doAxios } from '@/modules/common/api';
import { CommonRequest } from '@/modules/types/api/common';
import { ModuleResponse } from '@/modules/types/api/product';
const loadData = useCallback(async () => {
const path = `${path}`
const params: CommonRequest = {
pagingNo: 1,
pagingSize: 10,
pagingSort: `${pagingSort}`
}
const data = await doAxios<ModuleResponse>(path, params)
}, [])
이렇게 하면 data.resultCd, data.errMsg, data.pagingNo 등 CommonResponse interface에 정의한 값들에 바로 접근 가능하다.
동시에 ItemListResponse interface에 정의한 data.list에 접근 가능하다.
data.list에서 forEach, map 등의 메소드를 통해 각 배열의 인자의 키 값에도 접근 가능하다.
typescript가 없었다면 응답 값으로 무엇이 있는지 알 수 없고, 객체 안에 어떤 데이터가 있는지 알 수 없었을 텐데 type을 정의하니 자동으로 타입과 객체 추론이 가능하다!
멋져유