이 글은 아래 강의를 바탕으로 정리한 글입니다. 🤗
https://inf.run/UGoRu유틸리티 타입이란 제네릭, 맵드 타입, 조건부 타입 등의 타입 조작 기능을 이용해 실무에서 자주 사용되는 타입을 미리 만들어두고 TS가 자체적으로 제공해주는 특수한 타입들입니다.
📚 공식문서를 찾아보면 매우 많은 유틸리티 타입들이 있는데, 이중에서 자주 사용되는 핵심 유틸리티 타입은 약 9개입니다.
Partial<T> : 특정 객체 타입의 모든 프로퍼티를 선택적으로 만들어주는 유틸리티 타입Required<T> : 특정 객체 타입의 모든 프로퍼티를 필수적으로 만들어주는 유틸리티 타입Readonly<T> : 특정 객체 타입의 모든 프로퍼티를 readonly 프로퍼티로 만들어주는 유틸리티 타입Pick<T, K> : 특정 객체 타입에서 특정 프로퍼티만 선택하여 새로운 객체 타입을 만들어주는 유틸리티 타입Omit<T, K> : 특정 객체 타입에서 특정 프로퍼티만 제외하여 새로운 객체 타입을 만들어주는 유틸리티 타입Record<K, T> : K는 객체 프로퍼티 키를 유니온으로 받고 T는 키들의 value 타입을 받아 새로운 객체 타입을 만들어주는 유틸리티 타입Exclude<T, U> : T에서 U를 제거한 타입을 만들어주는 유틸리티 타입Extract<T, U> : T에서 U를 추출하여 새로운 타입을 만들어주는 유틸리티 타입ReturnType<T> : 함수의 반환값 타입을 추출하는 유틸리티 타입Partial<T>**Partial<T>**는 특정 객체 타입의 모든 프로퍼티를 선택적 프로퍼티로 변환합니다.
// Partial<T> 예시
interface Post {
title: string;
tags: string[];
content: string;
thumbnailUrl?: string;
}
// Partial<Post> 타입은 Post 타입의 모든 프로퍼티를 선택적으로 만들어주는 타입
const draft: Partial<Post> = {
title: "제목",
content: "내용",
};💡 임시 저장(Draft) 기능처럼 일부 프로퍼티만 입력받아야 하는 경우에 유용합니다.
Required<T>**Required<T>**는 특정 객체 타입의 모든 프로퍼티를 필수 프로퍼티로 변환합니다.
// Required<T> 예시
const withThumbnailPost: Required<Post> = {
title: "제목",
tags: ["1", "2", "3"],
content: "내용",
thumbnailUrl: "
https://example.com/thumbnail.jpg
",
};⚠️ 선택적 프로퍼티가 포함된 타입을 모두 필수로 만들어야 할 때 사용합니다. 위 예시에서
thumbnailUrl은 원래 선택적 프로퍼티지만, Required를 사용하면 반드시 제공해야 합니다.
Readonly<T>**Readonly<T>**는 특정 객체 타입의 모든 프로퍼티를 읽기 전용 프로퍼티로 변환합니다.
// Readonly<T> 예시
const readonlyPost: Readonly<Post> = {
title: "제목",
tags: ["1", "2", "3"],
content: "내용",
thumbnailUrl: "
https://example.com/thumbnail.jpg
",
};
// readonlyPost.title = "제목2";
// ❌ 오류 발생, readonly 프로퍼티는 수정 불가🚨 객체를 생성한 후 수정되어서는 안 되는 불변 데이터를 다룰 때 유용합니다.
Pick<T, K>**Pick<T, K>**는 특정 객체 타입에서 원하는 프로퍼티만 선택하여 새로운 객체 타입을 만듭니다.
interface Post {
title: string;
tags: string[];
content: string;
thumbnailUrl?: string;
}
// Pick<T, K> 예시
// Post 타입에서 title과 content 프로퍼티만 선택하여 새로운 객체 타입을 만듦.
const legacyPost: Pick<Post, "title" | "content"> = {
title: "옛날 제목",
content: "옛날 내용",
};💡 큰 객체 타입에서 필요한 일부 프로퍼티만 사용하고 싶을 때 유용합니다.
Omit<T, K>**Omit<T, K>**는 특정 객체 타입에서 특정 프로퍼티만 제외하여 새로운 객체 타입을 만듭니다.
interface Post {
title: string;
tags: string[];
content: string;
thumbnailUrl?: string;
}
// Omit<T, K> 예시
// Post 타입에서 title 프로퍼티를 제외하여 새로운 객체 타입을 만듦.
const NoTitlePost: Omit<Post, "title"> = {
// title: "최신 제목", // ❌ 오류 발생, title 프로퍼티가 제외되었기 때문
tags: ["1", "2", "3"],
content: "최신 내용",
thumbnailUrl: "
https://example.com/thumbnail.jpg
",
};💡 Pick과 반대 개념으로, 제외하고 싶은 프로퍼티가 적을 때 Omit이 더 편리합니다.
Record<K, T> ⭐️**Record<K, T>**는 객체의 키와 값 타입을 동시에 정의하여 새로운 객체 타입을 만듭니다.
예를 들어 화면 크기에 따라 3가지 버전의 썸네일을 지원한다고 가정했을 때, 화면 크기 별 url 타입을 별도로 정의하는데, 만약 여기에 watch 버전이 추가되어야 한다면 똑같이 생긴 프로퍼티를 하나 더 추가해주어야 하는 중복 코드가 발생하게 되는데 이럴 때, 다음과 같이 Record 타입을 이용하면 됩니다.
K에는 어떤 프로퍼티들이 있을지 String Literal Union 타입을 할당하고 T에는 프로퍼티의 값을 할당합니다.
// 레거시
type ThumbnailLegacy = {
large: { url: string };
medium: { url: string };
small: { url: string };
};
// Record<K, T> 예시
type Thumbnail = Record<"large" | "medium" | "small", { url: string }>;
// 만약 watch 키를 추가해야 한다면
type Thumbnail2 = Record<
"large" | "medium" | "small" | "watch",
{ url: string }
>;⭐ 동일한 구조의 프로퍼티가 여러 개 필요할 때 중복 코드를 줄일 수 있는 강력한 유틸리티 타입입니다.
Exclude<T, U>**Exclude<T, U>**는 T로부터 U를 제거하는 타입입니다.
// Exclude<T, U> 예시
// string | boolean 타입에서 boolean 타입을 제거한 타입을 만듦.
type A = Exclude<string | boolean, boolean>; // string 타입💡 Union 타입에서 특정 타입만 제외하고 싶을 때 사용합니다.
Extract<T, U>**Extract<T, U>**는 T로부터 U를 추출하는 타입입니다.
// Extract<T, U> 예시
// string | boolean 타입에서 boolean 타입을 추출한 타입을 만듦.
type B = Extract<string | boolean, boolean>; // boolean 타입💡 Exclude와 반대 개념으로, Union 타입에서 특정 타입만 추출하고 싶을 때 사용합니다.
ReturnType<T>**ReturnType<T>**는 타입변수 T에 할당된 함수 타입의 반환값 타입을 추출하는 타입입니다.
// ReturnType<T> 예시
function funcA() {
return "hello";
}
function funcB() {
return 10;
}
type C = ReturnType<typeof funcA>; // string 타입
type D = ReturnType<typeof funcB>; // number 타입💡 함수의 반환 타입을 별도로 정의하지 않고도 추출할 수 있어, 함수와 타입 간의 일관성을 유지하기 쉽습니다.