공통 타입 변환을 위한 유틸리티 타입
타입스크립트에서 제공하는 유틸리티 타입(Utility Types)은 type, interface를 입맛에 맞게 사용할 수 있도록 도와주는 유용한 기능이다.
유틸리티 타입의 종류는 다음 그림과 같이 매우 많다(타입스크립트 공식 페이지).
이 중 사용 빈도가 잦은 Partial, Pick, Omit, Record, Readonly에 대해 알아보자.
1. Partial
partial은 ‘부분적인’이라는 뜻으로, 정의된 타입의 속성을 모두 옵셔널로 사용하여 부분적으로 원하는 속성만 사용하도록 할 수 있다.
우선 Partial의 정의는 다음과 같다.
type Partial<T> = { [P in keyof T]?: T[P]; };
Partial<Type>의 방식을 통해 속성을 옵셔널하게 사용하며, 예시는 다음과 같다.
interface Hardware{ cpu: string; gpu: string; memory: number; storage: number; accessary: string; } const selectOptions = (default: Hardware, selected: Partial<Hardware>) => { setOptions({...default, ...selected}); }; const defaultOption = { cpu: "M1"; gpu: "10-core"; memory: 16; storage: 512; accessary: "Touch ID"; } const selectedOption = { cpu: "M2"; memory: "32"; storage: "1024"; }
이와 같은 방법으로 사용하지 않는 속성을 옵셔널로 변경하여 사용할 수 있다.
2. Pick
pick은 ‘뽑다’는 뜻으로, 정의된 타입에서 속성을 지정하여 사용할 수 있다.
Pick의 정의는 다음과 같다.
type Pick<T, K extends keyof T> = { [P in K]: T[P]; };
Pick<Type, Keys>의 방식을 사용해 사용할 속성을 문자열이나 유니온 타입으로 Keys에 지정하여 해당 속성만 사용한다.
interface Exercise{ title: string; type: string; time: number; complete: boolean; } type BriefExercise = Pick<Exercise, "title" | "complete">; const today = { title: "jogging"; complete: true; }
Partial은 모든 속성을 옵셔널로 사용하지만 Pick은 속성을 지정하여 필요한 타입만 정의하는 방식으로 사용한다.
3. Omit
omit은 ‘생략하다’라는 뜻으로, 정의된 타입에서 생략할 속성을 지정하여 사용할 수 있다.
Omit의 정의는 다음과 같다.
type Omit<T, K extends keyof any> = { [P in Exclude<keyof T, K>]: T[P] }
Omit<Type, Keys>의 방식으로 사용하며, Pick과 반대로 필요하지 않은 타입을 지정하여 정의하는 방식으로 사용한다.
interface Exercise{ title: string; type: string; time: number; complete: boolean; } type BriefExercise = Omit<Exercise, "type" | "time">; const today = { title: "jogging"; complete: true; }
Pick과 Omit의 용도는 같지만 정의 방법은 상반된다.
정의된 타입에서 생략하고 싶은 속성이 많을 때는 Pick, 생략하고 싶은 속성이 적을 때는 Omit을 사용하면 효과적이다.
4. Record
record는 ‘기록하다’는 뜻으로, key-value 세트를 생성하여 사용할 수 있다.
Record의 정의는 다음과 같다.
type Record<K extends string, T> = { [P in K]: T; };
Record<Keys, Type>의 방식으로 사용하며, 두 개의 타입에서 한 타입을 Keys, 한 타입을 Type으로 조합하여 사용할 수 있다.
type MacBookType = "air13" | "air15" | "pro13" | "pro14" | "pro16"; interface Performance{ cpu: string; memory: number; storage: number; }; const OnTheMarket: Record<MacBookType, Performance> = { air13: { cpu:"M1", memory:8, storage: 256 }; air15: { cpu:"M2", memory:16, storage: 512 }; pro13: { cpu:"M2", memory:16, storage: 1024 }; pro14: { cpu:"M2 pro", memory:32, storage: 1024 }; pro16: { cpu:"M2 ultra", memory:96, storage: 2048 }; }
위와 같은 방식으로 두 타입을 조합해서 사용할 수 있다.
5. Readonly
readonly는 ‘읽기 전용’이므로 타입을 읽기 전용으로 정의하여 사용할 수 있다.
Readonly의 정의는 다음과 같다.
type Readonly<T> = { readonly [P in keyof T]: T[P]; };
타입을 사용해 readonly 속성을 부여하고 싶은 경우에 사용할 수 있다.
interface LimitSize{ size: number; } const myData: Readonly<LimitSize> = { size: 32; } myData.size = 64; // error