Typescript 유틸리티 타입 - Partial, Omit, Record, Pick, Exclude, readonly

·2022년 11월 4일
0

타입스크립트를 좀 더 세련되게, 클린코드하게 작성하기!
유틸리티 타입을 잘 활용한다면 더욱 유지보수성 높고 잘 정의된 엄격한 타입을 정의할 수 있다😀
잘 만들어진 라이브러리들의 타입 정의 파일을 보면 이 유틸리티들을 굉장히 세련되게 잘 활용해두었다.
이를 본받아 나도 촘촘하고 쫜득한 타입을 작성하고 싶은데 막상 실제론 잘 생각나지 않을 때가 많다😅..
그래서 작성해보는 컨닝노트!
아래 예시들은 다 긁어온 거임. 하단에 출처있음


Partial

Partial<T>
T에 들어가는 프로퍼티를 선택적으로 사용할 수 있다!

interface Todo {
  title: string;
  description: string;
}
 
function updateTodo(todo: Todo, fieldsToUpdate: Partial<Todo>) {
  return { ...todo, ...fieldsToUpdate };
}
 
const todo1 = {
  title: "organize desk",
  description: "clear clutter",
};
 
const todo2 = updateTodo(todo1, {
  description: "throw out trash",
});

interface TODOtitle을 요구하지만 Partial로 구성되었기 때문에 오류가 나지 않는다!


Required

Required<T>

interface Props {
  a?: number;
  b?: string;
}
 
const obj: Props = { a: 5 };
 
const obj2: Required<Props> = { a: 5 }; // ERROR

선택적 프로퍼티로 구성된 Props 타입이지만 Required로 인해 필수로 설정되었다.
가끔 공통 타입을 돌려막기 하기 위해 속성들을 선택적으로 만드는 일들이 생긴다.
이 후 필수적으로 요구되는 컴포넌트에서도 선택적 요소가 되기 때문에 이로 인해 혼란이 빚어지는 경우가 있었는데, 해당 상황 때 Required하여 디버깅에 더욱 용이한 코드를 작성할 수 있을 것 같다.

Omit

omit<T,K>

interface Todo {
    title: string;
    description: string;
    completed: boolean;
}

type TodoPreview = Omit<Todo, 'description'>;

const todo: TodoPreview = {
    title: 'Clean room',
    completed: false,
};

T에서 K를 제거한 타입을 구성한다.

Exclude

Exclude<T,U>

type T0 = Exclude<"a" | "b" | "c", "a">;  // "b" | "c"

T에서 U를 뺀 나머지를 구성한다.

Record

Record<K,T>

interface PageInfo {
    title: string;
}

type Page = 'home' | 'about' | 'contact';

const x: Record<Page, PageInfo> = {
    about: { title: 'about' },
    contact: { title: 'contact' },
    home: { title: 'home' },
};
--- 하단의 인덱스 시그니쳐와 비슷함
type humanInfo = { 
  [index: string]: {title:string}
}

타입 T의 프로퍼티의 집합 K로 타입을 구성합니다.
사실, 이 유틸리티를 정리하고 싶어서 시작한 벨로그 글!

타입스크립트는 기본적으로 객체의 프로퍼티를 읽을 때 string 타입의 key 사용을 허용하지 않는다고 한다.
정확히는 string literal타입만 허용된다.

이로 인해 어떤 string값을 가져와 이로 key를 찾으려고 하면 타입에러가 난다.

for (const key of Object.keys(obj)) {
  console.log(obj[key]) // compile error! key가 string타입이다.
}

하지만 record를 사용하면, 더욱 보기 좋고 읽기 쉽게 프로퍼티를 맵핑할 수 있다!
난 이걸 모르고 그동안 인덱스 시그니쳐만 사용해왔다..

type humanType = {
  name: string;
  age: number;
  address: string;
};

type humanRecordType = Record<keyof humanType, string>;

let human: humanRecordType = {
  name: "또치",
  age: "20",
  address: "서울"
};

이거는 하단 출처의 블로그에서 발견한 사용 예시이다.
humanType을 Record로 다시 맵핑하여 string 값으로만 되어있는 타입을 구성했다.
깔끔하고 세련됐다😎

readonly

interface Todo {
    title: string;
}

const todo: Readonly<Todo> = {
    title: 'Delete inactive users',
};

todo.title = 'Hello'; // 오류: 읽기 전용 프로퍼티에 재할당할 수 없음

재할당이 일어나지 않게 한다는 것은, 내가 전달할 객체가 변하지 않을 것이라고 확신할 수 있다는 것!
함수 props에 readOnly를 주어서 불변성을 유지하는 안전장치를 마련할 수 있다.


기타

계속 작성중..


부록. enum, uion type,
https://ajdkfl6445.gitbook.io/study/typescript/enum-type-union-type


출처
https://developer-talk.tistory.com/296
https://kyounghwan01.github.io/blog/TS/fundamentals/utility-types/#partial
https://typescript-kr.github.io/pages/utility-types.html
https://radlohead.gitbook.io/typescript-deep-dive/type-system/readonly

profile
나 예인쓰, 응애인디

0개의 댓글