ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • TS: 인터페이스 구분하기 (ft. axios)
    Type Script 2022. 2. 9. 21:30

    인터페이스를 각 매개변수나 객체들에게 선언해주어야 타입스크립트의 가장 큰 장점, 실시간 타입검사가 가능하다.
    하지만 함수에 인터페이스를 적용할 때 가끔 그 결과의 구조가 어떻게될지 모르는 경우가 있다.
    그 대표적인 예가 api를 사용할 때라고 생각한다.

    interface iGreeting {
      data: string;
      status: number;
      message: string;
    }
    
    // 언제나 200 status 만 내려오진 않을 것이다. 
    
    const setGreeting = async (): string => {
      const response = axios.get(www.somthing.com);
    
      return response.data;
    }

    위의 예제에서 우리가 원하는 답안은 igreeting이라는 interface를 가진다.
    하지만 만일 에러객체가 response로 들어온다면 getGreeting은 response.data를 찾을 수 없을 것이고, 이는 타입에러로 연결될 것이다.

    사실 axios 가 제공하는 타입에는 axiosError라는 타입이 있어서 그 타입을 써도 된다. 하지만 interceptor에서 에러 객체를 다른 형태로 돌려준다고 가정해본다. 그럼 에러 객체의 인터페이스를 선언해서 or 연산자를 쓰면 해결되지 않을까?

    interface iGreeting {
      data: string;
      status: string;
      message: string;
    }
    
    // error interface 추가.
    // axiosError 를 interceptor에서 잡아서 저런 객체로 돌려준다고 가정.
    
    interface iError {
      status: number,
      message: string,
    }
    
    const setGreeting = async (): string | iError => {
      const response: iGreeting | iError = axios.get(www.somthing.com);
    
      return response.data;
    }

    아니면 iError와 iGreeting 은 비슷하게 생겼으니 optional data를 설정해 interface를 하나로 합쳐보는 것도 가능할 것 같다.

    interface iGreetingResponse {
      data?: string; // error 객체는 data가 없다.
      status: number;
      message: string;
    }
    
    const setGreeting = async (): string | iError => {
      const response: iGreetingResponse | iError = axios.get(www.somthing.com);
    
      return response.data;
    }

    하지만, 타입스크립트는 이 식에 불만을 가진다.
    이유인즉슨, error 형태의 response가 들어올 때에는 response.data가 존재하지 않기 때문에 response.data를 돌려줄 수 없다는 것이다. 만일 insterface의 종류를 알아내는 제네릭 함수로 iGreeting 처럼 생긴 response가 나올 때만 response.data를 리턴한다면 타입스크립트도 불평하지 않을 것이다.

    다시 위로 돌아가서 iGreetingResponse 와 iError 두 가지의 interface를 이용하며, interface가 iGreeting 처럼 생겼는지 안 생겼는지 구분할 수 있는 제네릭 함수를 만들어준다.

    interface iGreeting {
      data: string;
      status: string;
      message: string;
    }
    
    interface iError {
      status: number,
      message: string,
    }
    
    // T 처럼 생긴 interface를 가졌다면 그 안의 object.data를 리턴하도록 만들었다. 
    // 만일 T 처럼 생기지 않았다면 object.data는 없는 값이기 때문에 undefined를 반환한다.
    
    const checkResponseInterface = <T>(object: T): object is T => {
      return object.data
    }
    
    const setGreeting = async (): string | iError => {
      const response: iGreeting | iError = axios.get(www.somthing.com);
      const responseData = checkResponseInterface<iGrreting>(response);
    
      if (responseData) {
        return response.data;';
      }
    
      return response;
    }
    
    // responseData가 truthy라면 (존재한다면) response.data를 돌려주고
    // responseData가 falsy라면 (iError의 형태로 돌아온다면) response를 통으로 돌려준다.

    댓글

Designed by Tistory.