사이드 프로젝트를 하면서 여느때와 같이 Axios 인스턴스를 만들어서 사용하고 있다.
칸반 리팩토링을 하면서 Generics을 사용해 서버에서 만들어주는 응답값 인터페이스를 만들고, 각 api 함수를 선언시 Generics에 들어갈 타입을 지정해주도록 수정해서 pr을 올렸었다.
// apis/kanban.ts
interface IResponse<T> {
success: boolean;
error: any;
data: T;
}
export const fetchKanbanList = async (): Promise<IResponse<IKabanData[]>> => {
const data: IResponse<IKabanData[]> = await goHigerApi.get('/v1/applications/kanban');
return data;
};
첨엔 나름 괜찮은것같다고 생각했지만... 보다보니 깔끔하지 않았다.
또, pr 리뷰 중에 응답값 인터페이스를 axios 인스턴스 부분에서 공통적으로 적용하자는 의견이 있어서 검색해보았는데 비슷한 글들이 많았다.
여러 개 글을 참고해서 인스턴스를 클래스로 캡슐화하고, http 메서드별로 타입을 지정한 커스텀 메서드를 만들었다.
// apis/index.ts
import axios, { AxiosResponse, InternalAxiosRequestConfig } from 'axios';
interface ICommonResponse<T> {
success: boolean;
error: any;
data: T;
}
class ApiService {
private api;
constructor() {
this.api = axios.create({
baseURL: process.env.REACT_APP_BASE_URL,
withCredentials: true,
});
this.api.interceptors.request.use(
...
);
this.api.interceptors.response.use(
async (response: AxiosResponse) => {
if (!response.data.success) {
throw new Error(response.data.error);
}
return response;
},
error => {
return Promise.reject(error);
},
);
}
public async commonRequest<T>(
method: 'get' | 'post' | 'put' | 'patch' | 'delete',
url: string,
data?: any,
config?: InternalAxiosRequestConfig,
): Promise<ICommonResponse<T>> {
const response = await this.api[method](url, data, config);
return response.data;
}
public Get = async <T>(url: string, config?: InternalAxiosRequestConfig) =>
this.commonRequest<T>('get', url, undefined, config);
public Post = async <T>(url: string, data?: any, config?: InternalAxiosRequestConfig) =>
this.commonRequest<T>('post', url, data, config);
public Put = async <T>(url: string, data?: any, config?: InternalAxiosRequestConfig) =>
this.commonRequest<T>('put', url, data, config);
public Patch = async <T>(url: string, data?: any, config?: InternalAxiosRequestConfig) =>
this.commonRequest<T>('patch', url, data, config);
public Delete = async <T>(url: string, config?: InternalAxiosRequestConfig) =>
this.commonRequest<T>('delete', url, undefined, config);
}
export default new ApiService();
// apis/kanban.ts
import ApiService from 'apis';
...
export const fetchKanbanList = async () => {
const data = await ApiService.Get<IKabanData[]>('/v1/applications/kanban');
return data;
};
commonRequest 함수의 반환값 지정 타입인 Promise<ICommonResponse<T>>
은 AxiosResponse
타입의 data에 해당하게 된다.
아래는 AxiosResponse
타입의 내용이다.
// node_modules/axios/index.d.ts
export interface AxiosResponse<T = any, D = any> {
data: T;
status: number;
statusText: string;
headers: RawAxiosResponseHeaders | AxiosResponseHeaders;
config: InternalAxiosRequestConfig<D>;
request?: any;
}
그간 Typescript를 소극적으로 사용해왔었는데, 제네릭을 함수 파라미터처럼 사용한다는 것을 알게되었고, 앞으로 더 적절하게 사용하면 편리하지 않을까 생각이 들었다.
'Language > Typescript' 카테고리의 다른 글
[Typescript ] Nullish Coalescing ( || vs ?? ) (0) | 2023.07.25 |
---|---|
[Typescript] styled Components Typescript Definitions (0) | 2023.01.07 |
[Typescript] Typescript Tutorial (0) | 2023.01.03 |