반응형
250x250
Notice
Recent Posts
Recent Comments
Link
관리 메뉴

짧은코딩

타입 반복 줄이기(필독) 본문

TS/이펙티브 타입스크립트

타입 반복 줄이기(필독)

5_hyun 2023. 2. 23. 15:43

타입 반복

개발자라면 코드의 반복을 줄이려고 노력한 적이 분명 있을 것이다. 이런 것을 DRY(don't repeat yourself)라고 한다. 이것을 타입에도 적용하여 타입 반복 또한 줄여야 한다.

이 글은 두고두고 많이 봐야 한다고 생각한다. 왜냐하면 평소에 코드 중복을 굉장히 많이 하여 개발했기 때문이다. 그렇기에 개발을 할 때마다 이 글은 자주 챙겨보면서 타입 중복을 피하여 코딩해야겠다.

타입 반복 예시

-문제 코드

interface Person {
  firstName: string
  lastName: string
}

interface PersonWithBirthDate {
  firstName: string
  lastName: string
  birth: Date
}

나도 평소에 이렇게 타입이 겹치는 것이 있더라도 따로 분리하여 타입을 중복시켰다. 

타입 중복 해결 방법은 중복되는 시그니처를 명명된 타입으로 분리하거나 extends을 이용해 확장하면 된다.

 

-올바른 코드

interface Person {
  firstName: string
  lastName: string
}

interface PersonWithBirthDate extends Person {
  birth: Date
}

이렇게 extends를 사용해 타입 확장을 할 수 있다.

type PersonWithBirthDate = Person & { birth: Date };

혹은 이미 존재하는 타입을 확장하면 일반적이진 않지만 인터섹션 연산자 "&"를 이용할 수 있다. 이것은 확장할 수 없는 유니온 타입에 속성을 추가할 때 유용하다.

확장이 애매한 경우(Pick)

interface State {
  userId: string
  pageTitle: string
  recentFiles: string[]
  pageContents: string
}
interface TopNavState {
  userId: string
  pageTitle: string
  recentFiles: string[]
}

만약 State는 전체 애플리케이션의 상태이고 TopNavState는 부분만 표현하는 상태라면 TopNavState를 확장하여 State를 구성하는 것보다 State에서 속성을 빼내서 TopNavState를 구성하는 것이 좋다. 

 

-TopNavState

interface State {
  userId: string
  pageTitle: string
  recentFiles: string[]
  pageContents: string
}
// 1번
type TopNavState = {
  userId: State['userId']
  pageTitle: State['pageTitle']
  recentFiles: State['recentFiles']
}
// 2번
type TopNavState = {
  [k in 'userId' | 'pageTitle' | 'recentFiles']: State[k]
}

맨 처음엔 1번 방식으로 줄일 수 있겠지만 결국엔 2번 방식으로 하는 것이 코드 중복을 최소화하는 코드이다.

 

2번 코드에 마우스를 올린 사진

2번 코드에 마우스를 올리면 결국 똑같은 구성을 하고 있다는 것을 알 수 있다.

이러한 방식은 배열의 필드를 루프 도는 것과 같은 방식이다. 이 패턴은 표준 라이브러리에서 볼 수 있으며 Pick라고 한다.

 

-Pick

type TopNavState = Pick<State, 'userId' | 'pageTitle' | 'recentFiles'>

Pick로는 이렇게 구현할 수 있다. Pick는 제네릭 타입이며 두 개의 매개변수를 받아 결괏값을 반환하여 함수를 호출하는 것과 같은 효과이다. 

최소 중복으로 선택적 필드 만들기, 객체의 타입 만들기(keyof, Partial)

-keyof, Partial

keyof는 타입을 받아서 속성 타입의 유니온을 반환한다. 매핑된 타입인 [K in keyof Options]는 Options를 순회하며 K 값에 해당하는 속성이 있는지 찾는다. 이것 또한 표준 라이브러리에서 Partial이라는 이름으로 있다.

 

-최소 중복으로 선택적 필드 만들기

interface Options {
  width: number
  height: number
  color: string
  label: string
}
interface OptionsUpdate {
  width?: number
  height?: number
  color?: string
  label?: string
}

선택적 필드도 타입 중복을 최소화해서 만들 수 있다. 매핑된 타입과 keyof를 사용하면 Options로부터 OptionsUpdate를 만들 수 있다.

type OptionsUpdate = { [k in keyof Options]?: Options[k] }

이런 식으로 keyof를 활용하여 선택적 필드를 구현할 수 있다.

 

-객체의 타입 만들기

const INIT_OPTIONS = {
  width: 640,
  height: 480,
  color: '#00FF00',
  label: 'VGA',
}
type Options = typeof INIT_OPTIONS

이렇게 INIT_OPTIONS 객체를 타입으로 만들고 싶으면 typeof를 사용하면 된다.

Options에 마우스를 올린 사진

Options에 마우스를 올리면 이렇게 타입이 나오게 된다.

함수나 메서드 반환 값으로 타입 만들기(ReturnType)

function getUserInfo(userId: string) {
  // COMPRESS
  const name = 'Bob'
  const age = 12
  const height = 48
  const weight = 70
  const favoriteColor = 'blue'
  // END
  return {
    userId,
    name,
    age,
    height,
    weight,
    favoriteColor,
  }
}

type UserInfo = ReturnType<typeof getUserInfo>

이렇게 return 값의 타입을 선언하고 싶으면 ReturnType을 사용하면 된다.

UserInfo에 마우스를 올린 사진

이렇게 마우스를 올려보면 타입이 다 들어간 것을 볼 수 있다.

728x90
반응형
Comments