TIL67. Utility Type

조연정·2021년 1월 14일
0
post-thumbnail

고급 타입인 'utility type' 몇가지를 살펴보자.

유틸리티 타입

이미 정의해 놓은 타입을 변환할 때 사용하기 좋은 문법이다. 기존의 인터페이스, 제네릭 등의 기본 문법으로 충분히 타입을 변환할 수 있지만 유틸리티 타입을 사용하면 훨씬 간결한 문법을 타입을 정의할 수 있다.

자주 사용되는 유틸리티 타입

  • PICK

    특정 타입에서 몇 개의 속성을 선택하여 타입을 정의할 수 있다.
// 1) interface를 사용한 경우
interface Product {
    id: number;
    name: string;
    price: number;
    brand: string;
    stock: number;
}

//Product 중에 id, name, price만 가져온 interface 
interface ProductDetail {
    id: number;
    name: string;
    price: number;
}

//product에 일부 속성만 필요한 경우
function displayProductDetail(shoppingItem: ProductDetail);

위의 코드에서 알 수 있듯이 Product 인터페이스의 속성들이 ProductDetail 인터페이스도 중복된다. 점점 중복된 코드들이 많아져서 가독성이 나빠진다.

// 2) utility 사용한 경우
type ShoppingItem = Pick<Product, 'id'|'name'|"price">
function displayProductDetail(shoppingItem: ShoppingItem) {}

pick을 이용해서 기존에 타입에서 원하는 속성만 반환할 수 있다. 불필요하게 새로운 interface를 만들 필요가 없다.

  • Omit

    특정 타입에서 지정된 속성만 제거한 타입을 정의해준다.
interface AddressBook {
  name: string;
  phone: number;
  address: string;
  company: string;
}
const phoneBook: Omit<AddressBook, 'address'> = {
  name: '재택근무',
  phone: 12342223333,
  company: '내 방'
}
const chingtao: Omit<AddressBook, 'address'|'company'> = {
  name: '중국집',
  phone: 44455557777
}
  • Partial

    특정 타입의 부분 집합을 만족하는 타입을 정의할 수 있다.
interface Product {
    id: number;
    name: string;
    price: number;
    brand: string;
    stock: number;
}
// 1) '옵셔널 태그' 
interface UpdateProduct {
    id?: number;
    name?: string;
    price?: number;
    brand?: string;
    stock?: number;
}
// 'Product' 에서 특정 상품 정보(필요한 것만)를 업데이트하는 함수
function updateProductItem(productItem: UpdateProduct) {
...
} 

'Product' 인터페이스에서 필요한 정보만 골라서 업데이트하고 싶은 경우에 위 코드처럼 또 다른 인터페이스에 옵셔널 태그를 작성하여 만들어줄 수 있다. 하지만 가독성이 떨어진다.

// 2) 'partial'
type UpdateProduct = Partial<Product> 
function updateProductItem(productItem: Partial<Product>) {...
}

'partial'을 사용하여 원하는 속성만 골라 쓸 수 있다.

partial을 이용하여 코드 줄이는 과정

interface UserProfil {
    username: string;
    email: string;
    profilImgUrl: string;
}
// 프로필 사진이나 닉네임을 바꿀 경우 - 또 다른 interface를 만들어서 구현하기
interface UserProfilUpdate {
    username?: string;
    email?: string;
    profilImgUrl?: string;
}  
// 1.별도의 interface를 만들지 않고 기존의 인터페이스 재활용하기 - 속성타입을 인덱스로 접근
type UserProfilUpdate = {
    username?: UserProfil['username'];
    email?: UserProfil['email'];
    profilImgUrl?: UserProfil['profilImgUrl'];
}  
// 2.mapped type - 속성들을 반복문 돌려서 접근
type UserProfilUpdate = {
    [p in 'username' | 'email' | 'profilImgUrl']?: UserProfil[p]
}  
type UserProfilKeys = keyof UserProfil
// 3. union 타입을 keyof를 이용해 축약
type UserProfilUpdate = {
    [p in keyof UserProfil]?: UserProfil[p]
} 
// 4. 최종 partial 구현
type Subset<T> = {
    [p in keyof T]?: T[p]
}

Mapped Type

기존에 정의되어 있는 타입을 새로운 타입으로 변환해 주는 문법을 말한다. 타입에 map함수를 돌려서 새로운 타입을 반환한다고 생각하면 편하다.

맵드 타입 기본문법

{ [ P in K ] : T }
{ [ P in K ] ? : T }
{ readonly [ P in K ] : T }
{ readonly [ P in K ] ? : T }

맵드 타입 예제

type Heros = 'Hulk' | 'Capt' | 'Thor'
// 일반 타입 변수 'K'
type HeroAges = {[K in Heros]:number }
const ages: HeroAges = {
    Hulk: 33,
    Capt: 100,
    Thor: 1000
} 
profile
Lv.1🌷

0개의 댓글