티스토리 뷰

728x90

지금까지 타입스크립트를 다루면서 유틸리티 타입을 잘 사용하지 않는다는 것을 깨달았다. 특히, 유틸리티 타입에 대한 이해가 부족한 부분이 크다고 생각이 들었다. 。° ૮₍°´ᯅ`°₎ა °。 이번 기회에 다시 공부하고 다루어보면서 앞으로는 타입스크립트를 더 잘 활용할 수 있게 노력해야겠다.

 

 

:D 유틸리티 타입(Utility Type)

 

TypeScript에서 제공하는 특수한 형태의 타입을 의미한다. 이미 정의된 타입을 변환할 때 사용하는 문법으로, 유틸리티 타입을 활용하여 간결하게 타입을 정의할 수 있다. 이러한 타입은 크게 맵드 타입(mapped type)과 조건부 타입(conditional type)으로 나눌 수 있다.

 

맵드 타입(mapped type)이란, 기존에 정의된 타입을 새로운 타입으로 변환해주는 문법을 말한다. 

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

 

예를 들어 학생의 정보를 조회하는 API, 수정하는 API 두 개가 있을 때, ILearner 인터페이스에서 반복되는 구조를 활용하거나(방법1), 맵드 타입을 사용해 정의할 수 있다.(방법2)

(get) 'learners/:learnerId'
(patch) 'learners/:learnerId'
interface ILearner {
    name: string;
    grade: string;
    learningProgram: string;
    profileImageUrl: string;
};

// 타입 1
type TLearnerUpdate = {
    name?: ILearner['name'];
    grade?: ILearner['grade'];
    learningProgram?: ILearner['learningProgram'];
    profileImageUrl?: ILearner['profileImageUrl'];
};

// 타입 2
type TLearnerUpdate = {	[key in keyof ILearner]?: ILearner[key] };

 

조건부 타입(conditional type)은 조건에 따라 다른 타입을 선택할 수 있게 하는 문법을 말한다. 

condition ? TypeA : TypeB
type IsString<T> = T extends string ? string : never;
type Result1 = IsString<string>;
type Result2 = IsString<number>;

 

:D Pick<Type, Keys>

 

Type에서 프로퍼티 Keys만으로 구성된 타입을 생성할 때 사용한다. 특정 타입에서 선택한 프로퍼티만 포함하여 새로운 타입을 생성이 필요한 경우 사용한다. 

// Pick 기본 구조
type Pick<T, K extends keyof T> = {
  [P in K]: T[P];
};

예를 들어, 아래와 같이 TodoPreview가 정의되어 있을 때, 이미 정의된 Todo 타입에서 title과 completed 프로퍼티만 선택해 새로운 타입을 정의할 수 있다.

 

 

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

type TodoPreview = MyPick<Todo, 'title' | 'completed'>

 

(타입 챌린지 - 00004-easy-pick) Implement the built-in Pick<T, K> generic without using it. Constructs a type by picking the set of properties K from T.

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

type TodoPreview = MyPick<Todo, 'title' | 'completed'>

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

 

위 문제는 아래와 같이 풀이했다. K는 T 타입의 프로퍼티 집합 중 선택된 프로퍼티들을 의미한다. 여기서 K는 T 타입의 키(key)의 부분 집합을 나타내며, key in K를 사용하여 T 타입에서 선택된 프로퍼티들만 추출해 새로운 타입을 정의한다. 

type MyPick<T, K extends keyof T> = { [key in K] : T[key] };

 

Pick을 사용하여 문제를 해결한다면 아래와 같이 표현할 수 있다.

type MyPick<T, K extends keyof T> = Pick<T, K>;

 

 

:D Readonly<Type>

 

readonly 키워드는 특정 프로퍼티의 값을 초기화된 이후에는 값을 수정할 수 없게 한다. 주로 데이터의 불변성을 보장하기 위해 사용한다.

 

(타입 챌린지 - 00007-easy-readonly) Implement the built-in Readonly<T> generic without using it.

Constructs a type with all properties of T set to readonly, meaning the properties of the constructed type cannot be reassigned.

interface Todo {
  title: string
  description: string
}

const todo: MyReadonly<Todo> = {
  title: "Hey",
  description: "foobar"
}

todo.title = "Hello" // Error: cannot reassign a readonly property
todo.description = "barFoo" // Error: cannot reassign a readonly property

 

위 문제는 아래와 같이 풀이했다. readonly 키워드를 사용해 각 프로퍼티를 읽기 전용으로 설정하였다. 

type MyReadonly<T> = { readonly [key in keyof T] : T[key] };
해당 문제 또한 Readonly를 사용하면 아래와 같이 정의할 수 있다.
type MyReadonly<T> = Readonly<Todo1>;
 
 
728x90
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크