[타입스크립트 (5)] Type -2

SeHoony·2021년 9월 25일
1

TypeScript

목록 보기
5/7
post-thumbnail

이번 내용이 TypeScript에서 개념적으로 배워야 할 마지막 단계라고 생각한다. Type의 종류는 저번 'Type-1'에서 모두 배웠다. 이번에는 Type들을 가지고 변형(Transform)하는 방법에 대해서 배워보겠다.

1. Type Transform(타입 변환)

Type Transform의 기본은 index Type, Mapped Type, Conditional Type 이다. 이 세 Type들을 활용하여 TypeScript 자체적으로 제공하는 Utility Types들이 만들어졌다.

먼저 기본적인 Type(index, mapped, conditional)들을 살펴보고, Utilty Type들을 살펴보도록 한다.

1-1. core Type Transform

1) Index Type

'index'라는 단어에 주목하자. 이는 기존 Type에서 index만을 이용해 새로운 Type을 만들 때 이용한다. 바로 예시를 보자.

 // 기존의 Type Worker
  type Worker = {
    gender: "male" | "female"
    occupation: string
    work: () => {}
  }
  
  // index Type을 이용한 새로운 Type
  type developer = {
    gender: Worker["gender"] // index로 type을 가져옴
    occupation: Worker["occupation"]
    work: Worker["work"]
    brain: boolean
  }

2) Mapped Type

Mapped Type은 기존 Type을 유지하면서 약간의 변형을 줄 때 사용된다. 'map'은 배열에서 자주 쓰는 map 메서드와 비슷하다. type의 각 요소 type에 접근하여 어떠한 변형을 주는 것이다.

// 기존의 coffee type
type Coffee = {
    beans: number
    milk: boolean
    chocolate: boolean
    heating: "hot" | "iced"
  }

// utilty type 중에 partial Type을 구현해보았다.

type partial<T> = {
  [K in keyof T]?: T[K] 
  // T로 받을 type의 key들 하나하나에 '?' optional(?)을 붙여준다. 
}

const coffee: Coffee = {}
// Coffee Type은 각 요소들이 갖추어야 하기에 위의 coffee 객체는 에러가 난다.
const coffee: partial<Coffee> = {}
// Coffee Type의 각 요소는 모두 optional이기에 객체가 비어도 에러가 나지 않는다.

3) Conditional Type

조건(condition)에 따라 Type을 달리하겠다. 말그대로 이해하면 기분이 좋다. 조건을 걸어줄 때는 "A?B:C" 이 형식을 따라준다.

type TypeCheck<T> = T extends string ? number : boolean

type Type1 = TypeCheck<string> // --- Type은 number
type Type2 = TypeCheck<number> // --- Type은 boolean

지금까지 index Type, mapped Type, conditional Type를 살펴보았다. 이를 토대로 우리는 Utility types을 참말로 이해할 수 있는 지식을 얻었다고 보면 맘이 편할 거 같다.

1-2. Utility Types

1) Readonly

parameter로 받은 값을 function 내부에서 건들지 못하게 할 떄 주로 사용한다. 예시를 바로 보자!

type LoginData<I, P> = {id: I; pwd: P}

function login(loginData: Readonly<LoginData<string, number>>) {
  // loginData.id = // Readonly에서 loginData의 id, pwd 접근 시 에러 발생
  console.log(loginData)
}

2) Partial (vs) Required

Partial Type은 주로 Update 기능에서 활용도가 크다. Required Type는 partial과 사용하는 법은 똑같으면 반대의 기능을 한다. 예시는 Partial Type만 보기로 하자!

// 이번 예시는 개인 신상 정보의 미니미한 버전이다.
type Details = { 
    name: string
    nick: string
    job: boolean
    height: number
    weight: number
  }
// details을 update하는 함수이다. 
// 원본 details는 함수 내에서 변형이 가해지면 안되므로 Readonly Type을 썼다.
// 변경 Details는 Partial을 써서 변형된 부분만 객체로 받아 올 수 있다.
function updateDetails(
 origin: Readonly<Details>, updated: Partial<Details>
) {
    return {
      ...origin,
      ...updated,
    }
  }

3) Pick (vs) Omit

Pick의 뜻은 "고르다", Omit의 뜻은 "생략"이다. 각각의 기능은 그 뜻과 동일하다. 기존의 Type이 가지는 요소 Type 중에 쓸 것만 골라서 새로운 Type을 만들면 Pick, 안 쓸 것만 버려서 새로운 Type을 만들면 Omit을 쓴다. 반대는 닮았다. 즉 둘은 비슷하게 기능을 한다.

// A회사와 B회사가 있다. 각 회사들이 지원자에게 바라는 개인 신상정보가 차이가 날 때를 가정했다.

type Details = {
    name: string
    nick: string
    job: boolean
    height: number
    weight: number
  }

function detailsForACompany(details: Pick<Details, "name" | "job">) {
  return details
}
function detailsForBCompnay(details: Omit<Details, "nick" | "height" | "weight">) {
  return details
}
// 결국 A회사나 B회사나 결과값은 같게 된다.

4) Record

두 개의 Type을 묶는다고 생각하면 가장 빠르게 이해된다. 하지만 조금의 찝찝함이 남는 것이 수평적으로 묶는 것이 아니라 수직적이기 때문이다. 예시부터 보자.

type Friends = "Chu" | "Taeyeon" | "IU"

  type Details = {
    name: string
    nick: string
    job: boolean
    height: number
    weight: number
  }

  const friendDetails: Record<Friends, Details> = {
    Chu: {
      name: "츄",
      nick: "츄",
      job: true,
      height: 180,
      weight: 180
    },
    Taeyeon: { 
      name: "태연", 
      nick: "탱구", 
      job: true, 
      height: 180, 
      weight: 180 
    },
    IU: { 
      name: "이지은", 
      nick: "이지금", 
      job: true, 
      height: 180, 
      weight: 180 
    },
  }
}

이런 식으로 Friends Type 내에 Details Type이 안기는 형태로 묶이게 된다. 이러한 형태는 대부분의 데이터 베이스의 형식과 비슷하다. 따라서 Type이름도 Record가 아닌가 예상해본다.


2. Conclusion!

쉽게 생각하자. Type이 그냥 있는데 상황에 따라 Type을 변형시킬 필요성이 생긴 것이다. 대부분 Utiltiy Type을 써서 쉽게 Type Transform이 가능하고, Utility Type을 이해하기 위해서는 Index Type, Mapped Type, Conditional Type 등의 이해가 필수적이다.

profile
두 발로 매일 정진하는 두발자, 강세훈입니다. 저는 '두 발'이라는 이 단어를 참 좋아합니다. 이 말이 주는 건강, 정직 그리고 성실의 느낌이 제가 주는 분위기가 되었으면 좋겠습니다.

0개의 댓글