Typescript & React 재밌게 사용해보기

Gn0lee·2023년 5월 27일
0

Tech 이모저모

목록 보기
15/18

Typescript를 사용하게된 계기

처음 react 프로젝트를 진행할 때 typescript의 존재를 몰랐다. 당시 프로젝트를 도와주시던 멘토님이 "typescript 쓰면 좋은데.." 라고 탄식하셨다. 그때는 다른 언어를 배울 여유가 없어서 그냥 흘려들었다. 당시 작업하던 과정을 생각해보면, 머리속으로 구상 -> 코드 작성 -> 실행 -> 흰 화면 -> 디버그 -> 흰 화면... 의 연속이었다. 처음에는 이것이 자연스러운 개발 과정이라 생각했다. 하지만 정글 수료 후 많은 회사들의 과제를 하면서 자연스럽게 typescript를 접하게 되었다. 그리고 회사에 입사하면서 본격적으로 사용하게 되었다.

Typescript를 사용했던 방식

typescript가 사용되는 부분은 크게 api, redux의 slice, component의 props가 있다.
간단한 예시를 통해 내가 typescript를 사용했던 방식을 소개하려 한다. 예시의 상황은 todo list를 호출하고 todo list를 통해 Todo 컴포넌트를 렌더링 하는 것이다.
보일러 플레이트 코드는 생략하기로 한다.


export interface Todo {
	id: string;
  	title: string;
  	description: string;
	finish : boolean;
  	createdAt : string;
  	updatedAt : string;
}

export interface GetTodosApiResponse {
  statusCode: number;
  status: string;
  data : Todo[];
}

우선 Todo의 api를 통해 넘어오는 데이터의 타입을 지정해준다.


export default async function getTodosApi(){
  const { data } = await axios.get<GetTodosApiResponse>('/todos');
  
  return data;
}

그리고 선언한 api 데이터 타입을 api 호출 함수에서 사용한다.

컨테이너 컴포넌트에서 api를 호출하여 todo 리스트를 조회하고 todo 리스트를 map 메소드를 통해 Todo 컴포넌트들을 렌더링 한다. 그렇다면 Todo 컴포넌트는 아래와 같다.


interface TodoProps {
	id: string;
  	title: string;
  	description: string;
	finish : boolean;
}

export default function Todo({ id, title, description, finish}: TodoProps){
  ...
}

Todo 컴포넌트에서는 Todo에 해당되는 값들을 props로 전달받으며 컴포넌트 내에서 props의 타입을 선언한다.

의문점

처음 위와 같은 방식으로 사용할 때는 큰 의문점은 없었다. 하지만 시간이 지나면서 내가 새로운 기능을 구현할때 interface를 복사 붙여넣기 하고 있다는 것을 깨달았다. 위의 코드를 보면 api response의 statusCode와 status는 모든 api에서 공통으로 사용하는 type이다. 그리고 TodoProps의 타입들은 Todo 인터페이스의 일부분이다. 이런 반복되는 타입의 코드 중복과 이미 선언된 인터페이스의 일부분만 사용할 수 없을까? 라는 의문이 생겼다.

해결방법

내가 가진 의문점을 해결하기위해 타입스크립트의 제너릭, Pick, Omit을 사용했다. 우선 제너릭을 통해 중복되는 인터페이스 선언을 줄였다.

우선 아래는 제너릭을 통해 중복 코드를 줄이는 예시이다.


export interface ApiResponse<Data>{
  statusCode: number;
  status: string;
  data : Data;
}


export default async function getTodosApi(){
  const { data } = await axios.get<ApiResponse<Todo[]>>('/todos');
  
  return data;
}

제너릭을 통해 변경되는 부분의 타입만 설정하게 하였다.

아래는 Pick, Omit을 통한 Props 중복코드를 개선하는 코드이다.

export default function Todo({ id, title, description, finish}: Pick<Todo, 'id' | 'title' | 'description' | 'finish'>){
  ...
}

Pick을 통해 interface의 일부분만 고를 수 있다. 골라야 하는 Key가 너무 많다면 Omit을 통해 특정키만 제외시킬 수 있다.

후기

interface을 중복으로 선언할때 문제는 작업 효율보다 데이터 타입의 관리라 생각한다. 만약 Todo의 finish 타입이 boolean에서 다른 타입으로 변경되는 경우를 생각해보자. 이전 코드의 경우는 finish 로 선언된 부분을 모두 일일이 변경해 주어야한다. 그리고 TodoProps의 finish 타입을 수정해 주지 않으면 Todo 컴포넌트 내부에서는 에러가 발생하지 않는다. 물론 Todo 컴포넌트 호출하는 부분에서 에러가 발생하겠지만 todo 데이터의 흐름을 따라다니며 일일이 에러를 수정해주어야 한다. 마치 아래 짤처럼..

그에 반해 제너릭, Pick, Omit등을 사용하면 타입의 변경에 따라 유연하게 대처가 가능하다. todo 데이터가 흘러가는 코드들에서는 에러가 발생하지 않고 finish를 사용하는 코드에서만 에러가 발생할 것이다. 타입스크립트에는 정말 많은 타입들이 있다. 이를 통해 코드의 중복을 줄이고 개발 경험을 더욱 개선시킬 수 있을것이다. 앞으로 할일은 에러 repsonse에 대한 에러 처리이다. 기존에는 에러의 타입을 any로 지정하여 사용하였는데 이러면 기존 Javascript와 다를바가 없다. 다른 자료들을 찾아서 새로운 방법을 찾아 나가려 한다.

profile
정보보다는 경험을 공유하는 테크 블로그입니다.

0개의 댓글