[TypeScript] 유틸리티 타입

Jeris·2023년 6월 9일
0

TypeScript

목록 보기
10/11
post-custom-banner

유틸리티 타입

유틸리티 타입(utility type)이란 타입스크립트가 자체적으로 제공하는 특수한 타입들입니다. 우리가 지금까지 배웠던 제네릭, 맵드 타입, 조건부 타입 등의 타입 조작 기능을 이용해 실무에서 자주 사용되는 유용한 타입들을 모아 놓은 것을 의미합니다.

예를 들어 다음과 같이 Readonly<T>와 같은 유틸리티 타입을 이용해 특정 객체 타입의 모든 프로퍼티를 읽기 전용 프로퍼티로 변환할 수 있습니다.

interface Person {
  name : string;
  age : number;
}

const person : Readonly<Person> ={
  name : "이정환",
  age : 27
}

person.name = '' // ❌ No

다음과 같이 Partial<T> 유틸리티 타입을 이용해 특정 객체 타입의 모든 프로퍼티를 선택적 프로퍼티로 변환할 수 있습니다.

interface Person {
  name: string;
  age: number;
}

const person: Partial<Person> = {
  name: "이정환",
};

타입스크립트는 굉장히 다양한 유틸리티 타입을 제공합니다.

참조: TypeScript: Documentation - Utility Types


Partial, Required, Readonly

Partial

Partial은 타입스크립트의 유틸리티 타입 중 하나로, 객체의 모든 프로퍼티를 선택적으로 만듭니다. 즉, Partial<T>T의 모든 프로퍼티를 optional하게 만드는 새로운 타입을 생성합니다. 이는 기존의 객체 타입에서 필요한 일부만 사용하거나, 일부 프로퍼티의 값만 초기화하고 싶을 때 유용하게 사용할 수 있습니다.

interface Post {
  title: string;
  tags: string[];
  content: string;
  thumbnailURL?: string;
}

// Partial<T> 구현해보기
type Partial<T> = {
  [key in keyof T]?: T[key];
};

const draft: Partial<Post> = {
  title: "제목 나중에 짓자",
  content: "초안...",
};

Required

Required는 모든 프로퍼티를 필수 프로퍼티로 변환합니다. 즉, 선택적 프로퍼티를 가진 타입에서 모든 프로퍼티를 필수적으로 제공하도록 강제하는 유틸리티 타입입니다.

// Required<T> 구현해보기
type Required<T> = {
  [key in keyof T]-?: T[key];
};

const withThumbnailPost: Required<Post> = {
  title: "한입 타스 후기",
  tgas: ["ts"],
  content: "",
  thumbnailURL: "https://...",
};

Readonly

Required는 특정 객체 타입의 모든 프로퍼티를 읽기 전용 프로퍼티로 변환합니다.

// Readonly<T> 구현해보기
type Readonly<T> = {
  readonly [key in keyof T]: T[key];
};

const readonlyPost: Readonly<Post> = {
  title: "보호된 게시글 입니다.",
  tags: [],
  content: "",
};

readonlyPost.content = ""; // ❌ No

Pick, Omit, Record

Pick

Pick<T, K>T 타입의 프로퍼티 중 K로 지정한 프로퍼티만을 포함한 새로운 타입을 만듭니다.

interface Post {
  title: string;
  tags: string[];
  content: string;
  thumbnailURL?: string;
}

// Pick<T, K> 구현해보기
type Pick<T, K extends keyof T> = {
  [key in K]: T[key];
};

const legacyPost: Pick<Post, "title" | "content"> = {
  title: "엣날 글",
  content: "옛날 컨텐츠",
};

Omit

Omit<T, K>T 타입의 프로퍼티 중 K로 지정한 프로퍼티를 제외한 새로운 타입을 만듭니다.

// Omit<T, K> 구현해보기
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
// T = Post, K = "title"
// Pick<Post, Exclude<keyof Post, "title">>
// Pick<Post, Exclude<"title" | "content" | "tags" | "thumbnailURL", "title">>
// Pick<Post, "content" | "tags" | "thumbnailURL">

const noTitlePost: Omit<Post, "title"> = {
  content: "",
  tags: [],
  thumbnailURL: "",
};

Reacord

Record<K, V> 유틸리티 타입은 K로 지정한 프로퍼티 키들이 V로 지정한 값을 가지는 객체 타입을 만듭니다.

type ThumbnailLegacy = { // 비효율적
  large: {
    url: string;
  };
  medium: {
    url: string;
  };
  small: {
    url: string;
  };
  watch: {
    url: string;
  }
}

// Record<K, V> 구현해보기
type Record<K extends keyof any, V> = {
  [key in K]: V;
};

type Thumbnail = Record<
  "large" | "medium" | "small",
  { url: string; size: number }
>;

Exclude, Extract, ReturnType

Exclude

Exclude<T, U>는 타입 T에서 U를 제외한 나머지 타입을 반환합니다.

// Exclude<T, U> 구현해보기
type Exclude<T, U> = T extends U ? never : T;
// 1 단계
// Exclude<string, boolean> |
// Exclude<boolean, boolean>

// 2 단계
// string |
// never

// 최종적으로는
// string

type A = Exclude<"string" | "boolean", "string">; // A = boolean

Extract

Extract<T, U>는 타입 T에서 U와 일치하는 타입만을 추출합니다.

// Extract<T, U> 구현해보기
type Extract<T, U> = T extends U ? T : never;

type B = Extract<string | boolean, boolean>; // B = string

ReturnType

ReturnType<T>는 함수 T의 반환값의 타입을 추출합니다.

type ReturnType<T extends (...args: any) => any> = T extends (
  ...agrs: any
) => infer R
  ? R
  : never;

function funcA() {
  return "hello";
}

function funcB() {
  return 10;
}

type ReturnA = ReturnType<typeof funcA>; // ReturnA = string
type ReturnB = ReturnType<typeof funcB>; // ReturnB = number

Reference

profile
job's done
post-custom-banner

0개의 댓글