타입스크립트는 유용한 유틸리티 타입을 제공하여 코드 작성과 유지보수를 더 쉽게 할 수 있도록 도와줍니다. 유틸리티 타입은 이미 정의되어 있는 타입 구조를 변경하여 재사용 하고 싶을때 주로 사용 됩니다. 이 유틸리티 타입은 타입스크립트에서 정의해놓은 내장 타입이기 때문에 설정파일의 lib 속성만 변경해주면 바로 사용 할 수 있습니다.
{
"complierOptions": {
"lib": ["ESNext"]
}
}
lib속성은 타입스크립트에서 미리 정의해 놓은 타입 선언 파일을 사용할 때 쓰이는 옵션입니다.
Pick은 T의 특정 프로퍼티(K)들만 선택하여 새로운 타입을 만듭니다.
interface User {
id: number;
name: string;
age: number;
email: string;
}
type UserIdAndName = Pick<User, 'id' | 'name'>; // id와 name 프로퍼티만 선택(여러개)
type UserAge = Pick<User, 'age'>; // 한개만도 가능
Omit은 T의 특정 프로퍼티(K)들을 제외한 새로운 타입을 만듭니다.
interface Product {
id: number;
name: string;
price: number;
description: string;
}
type ProductPreview = Omit<Product, 'description'>; // description 프로퍼티를 제외한 타입(한개)
type ProductSummary = Omit<Product, 'id' | 'description'>; // 여러개도 가능
Partial은 T의 모든 프로퍼티를 옵션 속성(?)으로 바꿉니다. 주로 HTTP PUT처럼 데이터를 수정하는 REST API를 전송할 때 사용됩니다.
interface User {
id: number;
name: string;
age: number;
}
function updateUser(user: Partial<User>): void {
// user의 프로퍼티는 모두 선택적으로 처리됨 아래와 같이 처리됨
// use: {
// id?:number;
// name?:string;
// age?:number;
// }
}
Required는 T의 모든 프로퍼티를 필수로 만듭니다. 선택적 프로퍼티를 필수로 변환할 때 유용합니다.
interface PartialUser {
id?: number;
name?: string;
age?: number;
}
const completeUser: Required<PartialUser> = {
id: 1,
name: 'Alice',
age: 30,
};
Readonly는 T의 모든 프로퍼티를 읽기 전용으로 만듭니다.
interface Config {
apiKey: string;
debugMode: boolean;
}
function getReadOnlyConfig(config: Readonly<Config>): void {
// config의 프로퍼티는 읽기 전용으로 처리됨
}
유니온 타입에서 특정 타입을 제외하고 싶을 때 사용합니다. K는 유니온 타입이여야 합니다. (Omit이랑 다른점)
type Animal = 'dog' | 'cat' | 'fish' | 'bird';
// 'cat'과 'fish'를 제외한 유형을 생성
type NoCatOrFish = Exclude<Animal, 'cat' | 'fish'>;
// 결과: type NoCatOrFish = "dog" | "bird"
일반적으로 TypeScript에서 딕셔너리는 키와 값의 쌍으로 이루어진 데이터를 의미합니다. JavaScript에서는 객체를 사용하여 딕셔너리를 만들 수 있습니다. TypeScript에서는 이러한 딕셔너리의 타입을 강력하게 정의할 수 있도록 도와주는 유틸리티 타입인 Record가 있습니다.
K는 key로 유니온 타입 또는 일반 type(string, number, symbol)이 될 수 있습니다. 만약 일반 type을 사용하면 해당 type은 시그니처 인덱스로 사용됩니다. 따라서 반드시 string, number, symbol 3개만 가능합니다.
그리고 T는 type이 들어옵니다. 일반 타입이 들어올수도 있지만 미리 정의해놓은 type이나 interface도 가능합니다.
type Fruit = 'apple' | 'banana' | 'orange';
type FruitInfo = Record<Fruit, { color: string; taste: string }>;
const fruits: FruitInfo = {
apple: { color: 'red', taste: 'sweet' },
banana: { color: 'yellow', taste: 'sweet' },
orange: { color: 'orange', taste: 'citrus' },
};