logo

DowanKim

3. 리팩터링 이후 usePostApi 제너릭 이슈

2025년 9월 11일

이게머니

어제 코드리뷰에서, 아래와 같이 createMethodHook을 사용해 중복 코드를 제거할 수 있엇습니다.

const createMethodHook = <TData, TVariables = void>(method: HttpMethod) => { return (url: string, options?: MutationApiOptions<TData, TVariables>) => useMutationApi<TData, TVariables>(method, url, options); }; export const usePostApi = createMethodHook('post'); export const usePutApi = createMethodHook('put'); export const usePatchApi = createMethodHook('patch'); export const useDeleteApi = createMethodHook('delete');

이후, 카카오로그인기능을 구현하며 usePostApi를 사용할 때, 아래와 같이 구현 중이엇습니다.

export const useKakaoLogin = () => { return usePostApi<KakaoLoginResponse, KakaoLoginRequest>('/login', { onSuccess: (data) => { // 로그인 성공 시 처리 console.log('카카오 로그인 성공:', data); // 토큰을 쿠키에 저장 (백엔드에서 HttpOnly로 설정하는 것이 더 안전) // 또는 로컬스토리지에 저장 if (data.access_token) { localStorage.setItem('access_token', data.access_token); } // 메인 페이지로 리다이렉트 window.location.href = '/home'; }, onError: (error) => { // 로그인 실패 시 처리 console.error('카카오 로그인 실패:', error); alert('로그인에 실패했습니다. 다시 시도해주세요.'); // 로그인 페이지로 리다이렉트 window.location.href = '/login'; }, }); };

리스펀스와 리퀘스트는 각각 api문서 기반의 토큰과 어쏘리제이션 코드 인터페이스 입니다.

다만, 현재 이러한 오류가 나타납니다.

Expected 0 type arguments, but got 2.

기존에 안나던 오류가 왜 갑자기 생겼나 생각해 봤을 때, 아마 createMethodHook을 따로 만들고

export const usePostApi = createMethodHook(’post’)를 하는 과정에서 제너릭이 고정? 되는, 제대로 이해한지는 모르겠지만 createMethodHook(’post’)를 호출할 때 제너릭 타입을 지정하지 않았기 때문에 TData와 TVariables가 기본값으로 고정되어, expected 0 type arguments, 즉 더이상 제너릭을 사용할 수 없는 상황인 것 같습니다.

물론 실행도 잘되고 npm run lint에서 잡히지는 않지만, 이렇게 함수 분리시 제너릭이 고정되어 더이상 받지 못하는 문제는 어떻게 해결하는지 궁금합니다.

생각해본 방법으로는,

1.기존의 방식으로 돌아가면 오류x

export const usePostApi = <TData, TVariables = void>( url: string, options?: MutationApiOptions<TData, TVariables>, ) => { return useMutationApi<TData, TVariables>('post', url, options); };

하지만 이는 근본적인 해결책이 아닙니다. 다시 코드반복문제가 부활합니다.

2.아래처럼 사용

export const useKakaoLogin = () => { return usePostApi('/login', { onSuccess: (data: unknown) => { const response = data as KakaoLoginResponse; // 로그인 성공 시 처리 }, onError: (error) => { }, }); };

unknown을 넘겨주고 그 안에서 다시 타입을 정해주는 건, 코드를 짜는 사람입장에서도 읽는사람입장에서도 약간 이해하기 어려울 것 같습니다.


해결했습니다. 제가 createMethodHook을 잘못 작성했던 것 같습니다.

기존에 단순히 중복을 제거한다고,

const createMethodHook = <TData, TVariables = void>(method: HttpMethod) => { return (url: string, options?: MutationApiOptions<TData, TVariables>) => useMutationApi<TData, TVariables>(method, url, options); }; export const usePostApi = createMethodHook('post'); export const usePutApi = createMethodHook('put'); export const usePatchApi = createMethodHook('patch'); export const useDeleteApi = createMethodHook('delete');

위와같이 createMethodHook을 구현했습니다.

그렇나 이렇게 구현하면 usePostApi를 선언하면서 TData와 TVariables 타입을 명시해주지 않아서, 기본값인 unknown과 void로 타입추론이 되고 고정되어, 더이상 제너릭 타입을 받을 수 없는 일반함수가 되는 문제가 있는 것 같습니다.

즉, createMethodHook이 반환하는 함수 자체가 제너릭 함수여야 되는 것이므로,

아래와 같이 수정하였습니다.

const createMethodHook = (method: HttpMethod) => { return <TData, TVariables = void>(url: string, options?: MutationApiOptions<TData, TVariables>) => useMutationApi<TData, TVariables>(method, url, options); };

이렇게 하면, 제너릭함수를 반환함으로써 usePostApi는 이제 호출될 대 마다 새로운 타입을 받을 수 있는 제너릭 함수로 사용이 가능하게 된 것 같습니다.