카테고리 없음

필터링으로 타입 안정성 높이기

Ahyeon, Jung 2024. 11. 5. 12:24

API의 응답값이 바뀌는 경우 배열이 갑자기 객체로 변하거나, 빈 배열이 아닌 null로 오거나 하는 경우가 종종 있다. 이렇게 되면 변경된 API가 배포되었으나, 클라이언트는 아직 배포를 못해 페이지 전체가 에러로 나타나기도 한다. 이러한 상황을 피하기 위해 예상하지 않은 타입은 거부하는 것이 좋다.

기존 API 매핑

기존에는 viewModel을 활용해서 아예 속성명을 다르게 가져왔다.

import { CourseCardType } from "@/components/Courses/CourseCard";

export type ResponseCoursesType = {
  id: number;
  title: string;
  short_description: string;
  is_free: boolean;
  enroll_type: number;
  logo_file_url: string;
};

export function mapCoursesToViewModel(
  courses: ResponseCoursesType[]
): CourseCardType[] {
  return courses.map((course) => ({
    id: course.id,
    title: course.title,
    description: course.short_description,
    isFree: course.enroll_type === 4 ? undefined : course.is_free,
    enroll_type: course.enroll_type,
    logoUrl: course.logo_file_url,
  }));
}

 

위의 함수를 통해 새로 매핑한 값들을 반환해주었다.

export default async function getCourses({
  currentPage,
  count = 20,
  keyword,
  options,
}: GetCoursesProps) {
  try {
    const offset = (currentPage - 1) * count;
  
    const { data } = await axios.get<{
      course_count: number;
      courses: ResponseCoursesType[];
    }>(`/courses`);

    const CourseViewModel = mapCoursesToViewModel(data.courses);

    return { totalCount: data.course_count, courses: CourseViewModel };
  } catch (e) {
    console.error(e);
  }
  return;
}

 

CardType으로 자동 매핑하기

위에서 mapCourseToViewModel의 경우,추가할 필드가 늘어나면 속성을 전부 손대야한다. CouseType에 속성을 추가했을 때, 자동으로 객체에 포함시키기 위해서 타입스크립트를 활용할 수 있다.

export function mapCoursesToViewModel(
  courses: ResponseCoursesType[]
): CourseCardType[] {
  return courses.map((course) => {
    const mappedCourse: Partial<CourseCardType> = {};

    Object.keys(course).forEach((key) => {
      if (key in ({} as CourseCardType)) {
        (mappedCourse as any)[key] = course[key as keyof ResponseCoursesType];
      }

      mappedCourse.isFree =
        course.enroll_type === 4 && typeof course.is_free === "boolean"
          ? undefined
          : course.is_free;

      mappedCourse.description = course.short_description;
      mappedCourse.logoUrl = course.logo_file_url;
    });

    return mappedCourse as CourseCardType;
  });
}

 

CouseCardType과 일치하는 값들을 객체로 넣어주고, 예외사항들을 처리하면, 타입이 가지고 있는 값들만 매핑해올 수 있다. API가 변경되었을 때, 타입만 수정해도 객체로 들어올 수 있도록 유연하게 처리할 수 있다.