타입스크립트의 Partial
유틸리티 타입은 주어진 타입의 모든 프로퍼티를 선택적(optional)으로 만드는 데 사용됩니다. 이는 주어진 타입에 기반한 객체를 생성할 때, 해당 객체가 모든 프로퍼티를 가질 필요가 없도록 해줍니다.
예를 들어, 다음과 같은 인터페이스가 있다고 가정해봅시다:
interface Todo {
title: string;
description: string;
}
이 인터페이스는 title
과 description
두 가지 프로퍼티를 모두 가진 객체를 요구합니다. 하지만 경우에 따라 title
만 있거나 description
만 있는 객체를 만들고 싶을 수 있습니다. 이럴 때 Partial
을 사용하여 둘 다 선택적인 프로퍼티를 가진 새로운 타입을 생성할 수 있습니다:
type OptionalTodo = Partial<Todo>;
이제 OptionalTodo
타입은 title
, description
둘 중 어느 것도 없거나 둘 다 있거나, 둘 중 하나만 있어도 유효한 타입이 됩니다:
let todo1: OptionalTodo = {}; // Valid
let todo2: OptionalTodo = { title: "Buy groceries" }; // Valid
let todo3: OptionalTodo = { description: "Buy fruits and vegetables" }; // Valid
let todo4: OptionalTodo = { title: "Buy groceries", description: "Buy fruits and vegetables" }; // Valid
Partial
은 특히 API에서 사용자로부터 입력을 받거나, 특정 필드만 업데이트하는 등의 상황에서 유용하게 사용됩니다.
타입스크립트의 Pick
유틸리티 타입은 기존 타입에서 원하는 특정 프로퍼티만 선택하여 새로운 타입을 구성하는 데 사용됩니다. 이렇게 함으로써 주어진 타입의 일부만을 포함하는 객체를 타입 체크할 수 있습니다.
예를 들어, 다음과 같은 인터페이스가 있다고 가정해 봅시다:
interface User {
id: number;
name: string;
email: string;
}
이 인터페이스는 id
, name
, email
총 3개의 프로퍼티를 모두 가진 객체를 요구합니다. 하지만 경우에 따라서 name
과 email
만을 가진 객체를 만들고 싶을 수 있습니다. 이럴 때 Pick
을 사용하여 두 프로퍼티만을 가진 새로운 타입을 생성할 수 있습니다:
type UserContact = Pick<User, 'name' | 'email'>;
이제 UserContact
타입은 name
과 email
두 가지 프로퍼티만을 요구합니다:
let contactInfo: UserContact = { name: "John Doe", email: "john@example.com" }; // Valid
만약 이 객체가 id
프로퍼티를 포함한다면 타입 에러가 발생하게 됩니다:
let contactInfo: UserContact = { id: 1, name: "John Doe", email: "john@example.com" }; // Error
Pick
은 주어진 타입에서 특정 프로퍼티만을 필요로 할 때, 즉 해당 타입의 부분 집합만을 다루고자 할 때 매우 유용합니다.
Omit
타입스크립트의 Omit<T, K>
유틸리티 타입은 타입 T
에서 프로퍼티 K
를 제거한 타입을 생성합니다. 이는 객체에서 특정 프로퍼티를 제거하고자 할 때 유용하게 사용됩니다.
예를 들어:
interface User {
id: number;
name: string;
email: string;
}
type UserWithoutEmail = Omit<User, 'email'>;
UserWithoutEmail
는 이제 email
프로퍼티를 제외한 User
의 나머지 프로퍼티(id
, name
)를 포함합니다.
Exclude
Exclude<T, U>
타입은 T
타입 중에서 U
에 할당할 수 없는 타입만을 추출합니다. 다시 말해, T
에서 U
에 포함된 타입을 제외합니다. 이는 일반적으로 유니온 타입에서 특정 타입을 제외하고 싶을 때 유용하게 사용됩니다.
예를 들어:
type T = number | string | boolean;
type Result = Exclude<T, boolean>;
Result
는 이제 number
와 string
만을 포함하며, boolean
은 제외됩니다.
Extract
Extract<T, U>
타입은 T
타입 중에서 U
에 할당할 수 있는 타입만을 추출합니다. 다시 말해, T
와 U
의 교집합을 형성합니다. 이는 일반적으로 유니온 타입에서 특정 타입만을 선택하고 싶을 때 유용하게 사용됩니다.
예를 들어:
type T = number | string | boolean;
type Result = Extract<T, string | boolean>;
Result
는 이제 string
과 boolean
만을 포함하며, number
은 제외됩니다.
이런 유틸리티 타입들은 복잡한 타입 작업을 수행하거나 특정 조건을 충족하는 타입을 생성할 때 매우 유용합니다.
Required
타입스크립트의 Required<T>
유틸리티 타입은 주어진 타입 T
의 모든 프로퍼티를 필수로 만듭니다. T
타입 내에 선택적 프로퍼티가 있다면, Required<T>
를 통해 그 프로퍼티들이 필수로 변경되어 새로운 타입이 형성됩니다.
예를 들어:
interface User {
id: number;
name?: string;
email?: string;
}
type RequiredUser = Required<User>;
이제 RequiredUser
타입은 id
, name
, email
모든 프로퍼티가 필수입니다.
Record
타입스크립트의 Record<K extends keyof any, T>
유틸리티 타입은 K
타입의 키와 T
타입의 값을 갖는 객체 타입을 생성합니다. 이 유틸리티는 주로 키-값 객체를 만들거나, 같은 형태의 값들로 구성된 객체를 만들고 싶을 때 사용됩니다.
예를 들어:
type ThemeStyles = Record<'dark' | 'light', CSSProperties>;
ThemeStyles
는 이제 'dark'와 'light' 두 키 각각에 CSSProperties 타입의 값을 매핑합니다.
Extract
Extract<T, U>
유틸리티 타입은 타입 T
에서 U
에 할당 가능한 타입들만 추출하여 새로운 타입을 생성합니다. 이는 주어진 타입 내에서 특정 서브셋을 추출할 때 사용됩니다.
예를 들어:
type T = 'a' | 'b' | 'c';
type U = Extract<T, 'a' | 'b'>; // 'a' | 'b'
U
는 T
에서 'a'와 'b' 타입만을 포함하게 됩니다.
이들 유틸리티 타입들은 타입스크립트를 사용할 때 복잡한 타입 작업을 수행하는데 있어 매우 유용한 도구입니다.
타입스크립트에서 infer
키워드는 타입 내에서 사용되며, 일반적으로 제네릭 형태의 조건부 타입에서 사용됩니다. infer
는 '추론하다' 라는 의미를 가지며, 주어진 위치에서 타입을 추론하고 그 추론된 타입을 사용할 수 있게 합니다. 이는 함수 반환값, 함수 매개변수, 클래스의 멤버 변수 등 다양한 위치에서 사용될 수 있습니다.
예를 들어, 함수의 반환 타입을 가져오는 유틸리티 타입을 만들어 보겠습니다:
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
여기서 infer R
는 T
가 함수 타입일 때 그 함수의 반환 타입을 R
에 할당합니다. 따라서 ReturnType<T>
는 T
타입의 함수의 반환 타입이 됩니다.
위의 유틸리티 타입을 사용하여 함수의 반환 타입을 추출해볼 수 있습니다:
type Func = () => string;
type R = ReturnType<Func>; // string
이렇게 infer
키워드를 통해 타입을 동적으로 추론하고 사용할 수 있게 됩니다. 이는 매우 동적인 타입 시스템을 만드는 데 매우 유용한 도구입니다.