타입스크립트로 공용 컴포넌트의 의도 전달하기

camel·2024년 7월 15일
0
post-thumbnail

공용 컴포넌트의 주요 포인트

공용 컴포넌트를 개발할 때 가장 중요한 것은 무엇일까요? 많은 사람들이 확장성과 재사용성을 꼽을 것입니다.
저는 여기에 더해 '접근성'도 매우 높은 순위에 있다고 생각합니다.

왜 접근성이 중요한가?

사람들은 복잡하거나 이해하기 어려운 것을 꺼립니다. 공용 컴포넌트도 마찬가지입니다.

  • 😕 사용하기 어렵거나
  • 🤯 의도를 파악하기 힘들면

➡️ 결과적으로 사용량이 줄어듭니다.

어떻게 하면 사람들이 이 컴포넌트를 찾아 사용하게 될까?라는 고민이 생겼습니다.

해결 방법: 타입스크립트 활용하기

과거에는 주로 테스트 코드로 컴포넌트의 의도를 전달했습니다. 가능하면 이 방법으로 진행하고 싶었지만, 시간과 비용이 들어서 작성하기 어려웠습니다.

그래서 타입스크립트를 통해 제가 작성한 의도를 효과적으로 전달하는데 중점을 두었습니다.

실제 사례: 검색 가능한 Dropdown 컴포넌트

최근에 제가 유지보수한 컴포넌트는 검색 기능이 있는 Dropdown이었습니다.

  1. 처음: 내부 상태만 관리하는 비제어 컴포넌트
  2. 기획 변경: 제어 가능한 기능 추가

초기 타입은 아래와 같이 작성하였습니다.

type Props = {
  // ... 다른 props
  controlledValue?: string;
  onControlledChange?: (value: string) => void;
};

위 코드의 문제점은 controlledValueonControlledChange 중 실수로 하나만 전달한다면 의도한대로 동작하지 않아서 디버깅 하는 시간이 추가적으로 들어서 효율적이지 못하다고 생각했습니다.

유니온 타입으로 문제 해결하기

해결책으로 저는 유니온 타입 사용하여 타입을 나누었습니다.
아래와 같이 작성하였습니다.

type BaseProps = {
  // ... 공통 props
};

type UncontrolledProps = BaseProps & {
  controlledValue?: never;
  onControlledChange?: never;
};

type ControlledProps = BaseProps & {
  controlledValue: string;
  onControlledChange: (value: string) => void;
};

export type SearchableDropdownProps = UncontrolledProps | ControlledProps;

위처럼 작성하면, controlledValue를 하나만 쓸 수 없고, 둘다 작성해야해서 안정성이 높아졌고, 사용법을 보지 않아도 알 수 있게 하였습니다.

또한 기본 타입을 넣어도 되었지만 타입을 명시적으로 UncontrolledProps도 작성하여서 의도를 전달하고자했습니다.

의도를 더 명확히: kind 속성 추가

더해서 컴포넌트의 의도를 모르고 작성하는 경우도 고민하였습니다.
더욱 명확히 전달하기 위해 kind라는 타입을 작성하여서 이 컴포넌트를 사용하는 사람이 어떠한 의드롤 갖고 사용하는지 자각할 수 있게 작성하였습니다.

type UncontrolledProps = BaseProps & {
  controlledValue?: never;
  onControlledChange?: never;
  kind: 'uncontrolled';
};

type ControlledProps = BaseProps & {
  controlledValue: string;
  onControlledChange: (value: string) => void;
  kind: 'controlled';
};

이렇게 하면 kind 타입을 정해서 작성하기 때문에 바인딩하는 타입을 되짚고 작성해야하니 제가 만든 의도를 전달할 수 있어서 개발자는 이제 의도를 알고 사용할 수 있을 것입니다

마치며

이런 방식의 타입 정의로 저는 아래 2문제를 해결할 수 있었습니다.

  • 📢 컴포넌트의 의도를 명확히 전달
  • 🛑 잘못된 사용을 방지

제가 고민한 것을 통해서 이러한 부분을 방지할 수 있었던 점이 좋았는데요.

앞으로도 타입스크립트를 적극 활용해 더 나은 컴포넌트를 만들어보고 싶습니다.

감사합니다!

profile
개발과 일을 잘하고 싶은 사람

0개의 댓글