티스토리 뷰
유틸리티 타입
유틸리티 타입이란 제네릭, 맵드 타입, 조건부 타입 등의 타입 조작 기능을 이용해 실무에서 자주 사용되는 타입을 미리 만들어 놓은 타입을 말한다.
이번 포스팅에서 살펴볼 유틸리티 타입은 아래와 같다.
1. 맵드 타입 기반의 유틸리티 타입
(1) Partial<T>
특정 객체 타입의 모든 프로퍼티를 선택적 프로퍼티로 바뀌는 타입이다.
따라서 기존 객체 타입에 정의된 프로퍼티들 중 일부분만 사용할 수 있도록 도와준다.
아래와 같이 블로그 플랫폼의 게시글 객체 Post
가 선언되어 있다고 하자.
interface Post {
title: string;
tags: string[];
content: string;
thumbnailURL?: string;
}
만약 게시글 임시 저장 기능이 필요하다면 어떻게 해야 할까?
이럴 때 쓰기 좋은 기능이 Partial<T>
유틸리티 타입이다.
// 임시 저장 포스트 객체
const draft: Partial<Post> = {
title: "임시",
content: "추후 수정예정",
};
Partial<Post>
타입은 모든 프로퍼티가 선택적 프로퍼티가 된 Post 타입과 같다.
Partial<T>
유틸리티 타입을 직접 구현하면 아래와 같다. 제네릭과 맵드 타입을 활용하여 구현 가능하다.
type Partial<T> = {
// 맵드 타입으로 정의하기
[key in keyof T]?: T[key];
};
(2) Required<T>
특정 객체 타입의 모든 프로퍼티를 필수 프로퍼티로 바꿔주는 타입을 말한다.
위의 Post 예시에서, 썸네일이 반드시 있어야 하는 게시글이 필요하다고 하자. 이때 Post 객체에서 썸네일 프로퍼티를 강제할 수 있도록 Required<T>
타입을 활용할 수 있다.
const withThumbnailPost: Required<Post> = {
title: "후기",
tags: ["Ts"],
content: "",
thumbnailURL: "",
};
위 withThumbnailPost는 이제 thumbnailURL 프로퍼티나 다른 프로퍼티를 생략하면 오류가 발생하게 될 것이다.
Required<T>
타입을 직접 구현해보면 아래와 같다.
type Required<T> = {
[key in keyof T]-?: T[key];
};
-?
는 ?가 붙어있는 선택적 프로퍼티가 있다면 전부 ?
를 제거하라는 의미이다.
(3) Readonly<T>
특정 객체의 모든 프로퍼티를 읽기 전용 프로퍼티로 변환하는 타입을 말한다.
위의 Post 예시에서, 절대 수정할 수 없는 게시글이 필요하다고 하자. 이때 Post 객체의 모든 프로퍼티를 수정 불가능한 읽기 전용
프로퍼티로 변환해주기 위해 Readonly<T>
타입을 활용할 수 있다.
const readonlyPost: Readonly<Post> = {
title: "",
tags: [""],
content: "",
};
Readonly<T>
도 아래와 같이 직접 구현할 수 있다.
type Readonly<T> = {
readonly [key in keyof T] : T[key]
}
(4) Pick<T,K>
객체 타입으로부터 특정 프로퍼티만 골라내는 타입을 말한다.
똑같이 Post 객체에서, 이전에 만들어진 썸네일과 태그가 없는 Post 객체가 필요하다면 어떻게 할까?
이럴 때 사용할 수 있는 것이 Pick<T,K>
유틸리티 타입이다. Post 객체에서 썸네일 프로퍼티와 태그 프로퍼티가 아닌 프로퍼미탄 뽑아올 수 있다.
const legacyPost: Pick<Post, "title" | "content"> = {
title: "옛날 글",
content: "옛날 콘텐츠",
};
Pick<T,K>
에서 T
에는 Post
가, K
에는 "title" | "content"
가 할당되면서 Post
객체에서 title
과 content
프로퍼티만 뽑아낸 객체 타입이 된다.
Pick<T,K>
타입도 아래와 같이 구현할 수 있다.
type Pick<T,K extends keyof T> = {
[key in K] : T[key]
}
이때 key들의 집합이 될 K가 반드시 T의 key로 구성되어있음을 보장하기 위해 K extends keyof T
라는 제약을 추가해야 한다.
(5) Omit<T,K>
객체 타입으로부터 특정 프로퍼티만 제외하는 타입을 말한다.
Pick
과는 반대의 기능을 수행한다고 보면 된다.
아래는 제목이 없는 Post 객체를 위해 Post 객체 타입에서 title 프로퍼티를 제외한 새로운 객체 타입을 정의한 예시이다.
const noTitlePost: Omit<Post, "title"> = {
content: "t",
tags: [""],
thumbnailURL: "",
};
Omit<T,K>
는 아래와 같이 직접 구현할 수 있다.
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
Exclude<keyof T, K>
로 T의 key 중에서 특정 프로퍼티 K가 제외된 key의 집합을 반환하고(key 제거),Pick<T, Exclude<keyof T,K>>
로 T에서 해당 집합의 key들만 골라서 새로운 객체 타입으로 만든다.
(6) Record<K,V>
객체 타입으로부터 인덱스 시그니쳐처럼 유연하지만 제한적인 타입을 정의할 때 사용한다.
블로그 Post 객체에서 화면 크기에 따라 3가지 버전의 썸네일을 지원하려고 할 때, Record<T,K> 타입을 이용하여 유연한 썸네일 객체 타입을 만들 수 있다.
type Thumbnail = Record<"large" | "medium" | "small", { url: string }>;
K
에는 "large" | "medium" | "small"
가 할당되어 large, medium, small 프로퍼티가 있는 객체 타입이 정의된다. 그리고 각 프로퍼티별 value의 타입은 V
에 할당한 {url : string}
이 된다.
Record<K,V>는 아래와 같이 구현할 수 있다.
type Record<K extends keyof any, V> = {
[key in K] : V
}
2. 조건부 타입 기반의 유틸리티 타입
(1) Exclude<T, U>
T에서 U를 제거하는 타입
직접 구현해보기
type Exclude<T, U> = T extends U ? never : T;
사용해보기
type A = Exclude<string | boolean, boolean>;
// 1 단계
// Exclude<string, boolean>
// Exclude<boolean, boolean>
// 2 단계
// string
// never
// 3 단계
// union : string
(2) Extract<T, U>
T에서 U를 추출하는 타입
직접 구현해보기
type Extract<T, U> = T extends U ? T : never;
사용해보기
type B = Extract<string | boolean, boolean>;
(3) ReturnType<T>
ReturnType
은 타입 변수 T에 할당된 함수 타입의 반환값 타입을 추출하는 타입이다.
function funcA() {
return "hello";
}
function funcB() {
return 10;
}
type ReturnA = ReturnType<typeof funcA>;
type ReturnB = ReturnType<typeof funcB>;
// 직접 구현
type ReturnType<T extends (...args: any) => any> = T extends (
...args: any
) => infer R
? R
: never;
본 포스팅은 인프런 한 입 크기로 잘라먹는 타입스크립트 강의를 기반으로 작성되었습니다. 사용된 이미지들은 모두 위 강의에서 가져왔습니다. 문제시 알려주세요.
'웹개발 > TypeScript' 카테고리의 다른 글
타입스크립트 | 타입 조작 - 인덱스드 엑세스 타입, keyof 연산자, mapped 타입, 템플릿 리터럴 타입, 조건부 타입 (0) | 2023.08.27 |
---|---|
타입스크립트 | 제네릭 (0) | 2023.08.26 |
타입스크립트 | 클래스 (0) | 2023.08.24 |
타입스크립트 | 인터페이스 (0) | 2023.08.24 |
타입스크립트 | 함수와 타입 (0) | 2023.08.24 |