Typescript

유틸리티 타입

sihanni 2024. 7. 8. 08:44

소개

유틸리티 타입은 이미 정의된 타입을 변형하여 사용할 때 사용한다.

 

유틸리티 타입

(Utility type)은 이미 정의되어 있는 타입 구조를 변경해서 재사용하고자 할 때 사용한다.

우선 타입스크립트 설정 파일 내 compilerOptions 속성을 체크해준다.

{
  "compilerOptions": {
    "lib": ["ESNext"]
  }
}

정보

(TypeScript 설정 파일인 tsconfig.json에서 compilerOptions는 TypeScript 컴파일러가 코드를 컴파일할 때 사용할 설정을 정의하는 속성이다. 해당 설정을 통해 컴파일러의 동작 방식을 제어하고, 프로젝트에 맞는 맞춤형 컴파일 환경을 구성할 수 있다.)

(ESNext는 JavaScript의 최신 기능과 업데이트를 포함하는 스펙을 가리키는 용어)

 

1. Pick

Pick 은 이미 존재하는 특정 타입의 속성을 뽑아서 새로운 타입을 만들어 낼 때 사용된다.

Pick<타겟 타입, '타겟 타입 내 추출할 속성 이름'
Pick<타겟 타입, '타겟 타입 내 속성 이름' | '타겟 타입 내 속성 이름2'>  (유니언 타입 형태로 사용 가능)

* Pick 유틸리티 타입에서 사용되는 <> 는 제네릭 문법이다.

즉, <>에서 넘겨진 타입으로 타입이 정의되는 것이다.

interface Profile {
  id: string;
  name: string;
  address: string;
}

type ProfileId = Pick<Profile, 'id'>;

type PrifileIdName = Pick<Profile, 'id' | 'name'>;

위의 예시는 Pick 이라는 유틸리티 타입을 이용한 것이다.

Profile 인터페이스의 id 속성을 추출해서 ProfileId라는 새로운 타입으로 정의한다.

 

2. Omit

특정 타입에서 속성 몇 개를 제외한 나머지 속성으로 새로운 타입을 생성할 때 사용된다.

Omit<타겟 타입, '타겟 타입 내 추출할 속성 이름'
Omit<타겟 타입, '타겟 타입 내 속성 이름' | '타겟 타입 내 속성 이름2'>  (유니언 타입 형태로 사용 가능)

문법 자체는 Pick과 다를바 없다.

interface UserProfile {
  id: string;
  name: string;
  address: string;
};

type User = Omit<UserProfile, 'address'>;

//결과
type User = {
  id: string;
  name: string;
};

 

3. Partial

특정 타입의 모든 속성을 모두 옵션 속성으로 변환한 타입으로 생성해준다.

Partial<타겟 타입>

타겟이 되는 타입의 "모든 속성" 을 옵션 속성으로 변경하는 것이기 때문에 타입 이름만 넘기면 된다.

타겟 타입의 속성을 모두 Optional하게 사용 가능하므로 보통 데이터 수정 API를 다룰 때 사용하면 좋다.

interface Todo {
  id: string;
  title: string;
  checked: boolean;
}

const updateTodo = (todo: Todo): void => {
 //...
}

위와 같은 경우 title이나 checked 상태만 수정하는 것을 대처하기엔 유연하지 못할 수 있다.

const updateTodo = (todo: Partial<Todo>): void => {
 //...
}
Partial 으로 대응하면 어떤 값으로 넘겨져도 처리하기 용이하다.

 

4. Exclude

유니언 타입을 변형한다. 

Exclude<대상 유니언 타입, '제거할 타입 이름'>
Exclude<대상 유니언 타입, '제거할 타입 이름1' | '제거할 타입 이름2'>
type Languages = 'C' | 'Java' | 'TypeScript' | 'React' ;

type TrueLanguages = Exclude<Languages, 'React'>;

//info
type Languages = "C" | "Java" | "TypeScript"

물론 인자로 유니언 타입을 넘기면 다수의 타입을 수정할 수 있다.

 

5. Record

타입 1개를 속성의 Key로 받고 다른 타입 1개의 속성 Value을 받아 객체 타입으로 변환해 준다.

Record<객체 속성의 키로 사용할 타입, 객체 속성의 값으로 사용할 타입>

첫 번째 제네릭 타입에는 string, number, string 유니언, number 유니언 등이 들어갈 수 있고,

두 번째 제네릭 타입에는 아무 타입이나 넣을 수 있다.

 

실제 값을 변경하는 것이 아니라 마치 map()을 쓰는 것과 같이 변환만 해준다.

잘만 사용하면 기존의 코드의 중복된 부분을 상당수 제거 할 수 있을 것으로 보인다.

type HeroProfile = {
  skill: string;
  age: number;
};
type HeroNames = 'thor' | 'hulk' | 'capt';

type Heroes = Record<HeroNames, HeroProfile>;

//info
type Heros = {
  thor: HeroProfile;
  hulk: HeroProfile;
  capt: HeroProfile;
}

Heros 타입의 형태는 객체고 키 값은 HeroNames로 이뤄져있고, 속성은 HeroProfile 타입의 형태를 취하고 있다.

Heros 타입을 이용하면 객체를 간단히 선언할 수 있게  되는 것이다.

type PhoneBook = Record<string, string>;

let familyPhones: PhoneBook = {
  dad: '010-1234-1234',
  mom: '010-4321-4321'
};

위와 같은 형태로도 사용할 수 있다.

 

6. Required

타겟 타입의 모든 속성을 필수속성으로 만든다.

Required<타겟 타입>
interface UserInfo {
  name: string;
  age: number;
  email: string;
  phone?: number;
}

const user:Required<UserInfo> = {
  name: 'ironman',
  age: '37',
  email: 'genius@a.com',
  phone: '1234-1234'
};

이때 phone 속성값이 없으면 에러가 발생한다.

 

7. Readonly

타겟 타입의 모든 속성을 읽기 전용으로 만들어 객체 속성을 수정하지 못하게 된다.

Readonly<타겟 타입>
const user:Readonly<UserInfo> = {
  name: 'ironman',
  age: 37,
  email: 'genius@a.com',
  phone: '1234-1234'
};

user.age = 38; // 에러 발생함 age는 readonly이므로

'Typescript' 카테고리의 다른 글

[TypeScript] module/ moduleResolution 에러 해결과 옵션 정리  (1) 2025.09.01
[TypeScript] TS Cheat Sheet (Type, Interface)  (0) 2025.08.19
배열 관련 메서드  (0) 2024.10.22
forEach vs for  (0) 2024.10.22
Shallow Copy, Deep Copy  (0) 2024.10.08