타입스크립트의 유틸리티 타입

타입스크립트의 유틸리티 타입

이 글은 타입스크립트의 유틸리티 타입에 대해 설명합니다.

YouTube Video

타입스크립트의 유틸리티 타입

타입스크립트 유틸리티 타입은 기존 타입을 기반으로 새로운 타입을 생성하기 위한 편리한 도구입니다. 이를 통해 더 유연한 타입 정의가 가능하며 코드 재사용성을 높일 수 있습니다. 여기서는 자주 사용되는 유틸리티 타입을 자세히 설명하고, 샘플 코드를 통해 각각의 사용 방법을 논의합니다.

Partial<T>

Partial<T>는 객체 타입의 모든 속성을 선택적으로 만듭니다 (undefined 허용). 원래 타입이 가진 일부 속성만 사용하고 싶을 때 유용합니다.

 1interface User {
 2  id: number;
 3  name: string;
 4  age: number;
 5}
 6
 7function updateUser(user: Partial<User>) {
 8  console.log(user);
 9}
10
11updateUser({ name: "Alice" }); // Updates only 'name'

설명:

위의 예에서 Partial<User>를 사용하면 User 타입의 모든 속성이 선택적으로 변경됩니다. 따라서 updateUser 함수에서 속성 중 일부만 전달할 수 있습니다.

Required<T>

Required<T>는 선택적 속성을 포함한 모든 속성을 필수로 만듭니다. 선택적인 속성을 필수로 변환하고 싶을 때 사용됩니다.

 1interface User {
 2  id: number;
 3  name?: string;
 4  age?: number;
 5}
 6
 7function createUser(user: Required<User>) {
 8  console.log(user);
 9}
10
11// createUser({ id: 1 }); // Error: 'name' and 'age' are required
12createUser({ id: 1, name: "Alice", age: 25 });

설명:

Required<User>를 사용하면 nameage와 같은 속성이 필수 속성으로 처리됩니다.

Readonly<T>

Readonly<T>는 객체의 모든 속성을 읽기 전용으로 만듭니다. 이것은 객체의 값이 변경되지 않도록 방지합니다.

 1interface User {
 2  id: number;
 3  name: string;
 4}
 5
 6const user: Readonly<User> = {
 7  id: 1,
 8  name: "Alice"
 9};
10
11// user.id = 2; // Error: 'id' is read-only
12console.log(user);

설명:

Readonly<T>를 사용하면 객체의 속성이 변경되는 것을 방지할 수 있습니다. 개발 중 데이터가 실수로 수정되는 것을 방지하고자 할 때 효과적입니다.

Record<K, T>

Record<K, T>는 지정된 키와 값 타입으로 맵 타입을 생성합니다. K는 키 타입(string 또는 number 등)이고, T는 값 타입입니다.

 1type Roles = "admin" | "user" | "guest";
 2interface Permissions {
 3  read: boolean;
 4  write: boolean;
 5}
 6
 7const rolePermissions: Record<Roles, Permissions> = {
 8  admin: { read: true, write: true },
 9  user: { read: true, write: false },
10  guest: { read: false, write: false },
11};
12
13console.log(rolePermissions);

설명:

Record<K, T>는 키-값 쌍을 정의하고자 할 때 유용합니다. 위의 예에서는 사용자 역할을 기반으로 권한이 정의됩니다.

Pick<T, K>

Pick<T, K>는 객체 타입에서 지정된 속성만 추출합니다. 필요한 속성만 추출하여 새로운 타입을 생성할 수 있습니다.

 1interface User {
 2  id: number;
 3  name: string;
 4  age: number;
 5}
 6
 7type UserSummary = Pick<User, "id" | "name">;
 8
 9const summary: UserSummary = {
10  id: 1,
11  name: "Alice"
12};
13
14console.log(summary);

설명:

Pick<T, K>를 사용하여 객체 타입에서 특정 속성만 추출하고 이를 새로운 타입으로 처리할 수 있습니다. 예를 들어, 위의 예에서는 idname만 추출됩니다.

Omit<T, K>

Omit<T, K>는 객체 타입에서 특정 속성을 제외합니다. 이는 Pick의 반대 작업입니다.

 1interface User {
 2  id: number;
 3  name: string;
 4  age: number;
 5  email: string;
 6}
 7
 8type UserWithoutEmail = Omit<User, "email">;
 9
10const userWithoutEmail: UserWithoutEmail = {
11  id: 1,
12  name: "Alice",
13  age: 25
14};
15
16console.log(userWithoutEmail);

설명:

Omit<T, K>를 사용하면 특정 속성을 제외하여 새로운 타입을 생성할 수 있습니다. 위의 예에서 email 속성이 제외됩니다.

Exclude<T, U>

Exclude<T, U>는 유니언 타입 T에서 타입 U를 제거하여 새로운 타입을 만듭니다. 특정 타입을 제거하고 싶을 때 사용됩니다.

1type Status = "active" | "inactive" | "pending";
2type ExcludedStatus = Exclude<Status, "pending">;
3
4const status: ExcludedStatus = "active"; // "pending" is excluded, so it cannot be chosen
5console.log(status);

설명:

Exclude<T, U>를 사용하면 유니언 타입 내에서 불필요한 타입을 제거할 수 있습니다. 위의 예에서 "pending"이 제외되었기 때문에, "active" 또는 "inactive"만 선택할 수 있습니다.

Extract<T, U>

Extract<T, U>는 유니언 타입 T 내에서 타입 U와 일치하는 부분을 추출합니다. 특정 타입만 추출하고 싶을 때 유용합니다.

1type Status = "active" | "inactive" | "pending";
2type ActiveStatus = Extract<Status, "active" | "pending">;
3
4const status: ActiveStatus = "active"; // "inactive" cannot be chosen
5console.log(status);

설명:

Extract<T, U>Exclude의 반대 작업을 수행합니다. 위의 예에서 "active""pending"만 선택할 수 있습니다.

NonNullable<T>

NonNullable<T>nullundefined를 제외한 타입을 생성합니다. 이 값들을 선택적 타입에서 제외하고 싶을 때 유용합니다.

1type UserName = string | null | undefined;
2type ValidUserName = NonNullable<UserName>;
3
4const name: ValidUserName = "Alice"; // null and undefined cannot be chosen
5console.log(name);

설명:

NonNullable<T>nullundefined를 포함한 타입에서 이들을 제외합니다. 값이 확실히 존재하도록 보장하고 싶을 때 유용합니다.

결론

TypeScript 유틸리티 타입은 타입 정의를 더 간결하고 유연하게 만드는 강력한 도구입니다. Partial, Required, Readonly, Record 등의 기본 유틸리티 타입을 이해하고 적절히 사용하면 코드 재사용성과 유지 관리성을 향상시킬 수 있습니다. 이 타입들을 숙달하면 더 견고하고 안전한 타입 정의를 할 수 있어 효율적인 개발이 가능합니다.

TypeScript의 keyof 연산자

TypeScript의 keyof 연산자는 객체 타입의 모든 속성 이름을 가져오는 데 사용됩니다. 이 연산자를 사용하여 객체 타입의 키를 유니온 타입으로 얻을 수 있습니다. 이는 타입 안전 코드를 작성하는 데 매우 유용합니다.

기본 사용법

1interface Person {
2    name: string;
3    age: number;
4    email: string;
5}
6
7// Use keyof to get the property names of Person
8type PersonKeys = keyof Person; // "name" | "age" | "email"

사용 예시

  1. 함수 인수에서 사용하기

    keyof를 사용하여 객체의 특정 속성을 기반으로 타입을 가지는 함수를 정의할 수 있습니다.

1function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
2    return obj[key];
3}
4
5const person: Person = { name: "Alice", age: 30, email: "alice@example.com" };
6const name = getProperty(person, "name"); // type is string
7const age = getProperty(person, "age");   // type is number
  1. 타입 제약 조건 강화하기

    keyof를 사용하면 함수에 전달된 키가 컴파일 타임에 유효성을 검사하도록 할 수 있습니다.

1// Passing an invalid property name results in an error
2const invalid = getProperty(person, "invalidKey"); // Error

요약

  • keyof 연산자는 객체 타입의 모든 속성 이름을 가져오는 데 사용됩니다.
  • 속성 이름을 유니온 타입으로 가져와 타입 안전 코드를 구현할 수 있습니다.
  • 함수 인수에서 이를 사용하여 함수가 유효한 속성 이름만 수락하도록 제한할 수 있습니다.

이와 같이, keyof 연산자는 TypeScript에서 타입 안전성을 강화하고 보다 견고한 코드를 작성할 수 있도록 도와줍니다.

위의 기사를 보면서 Visual Studio Code를 사용해 우리 유튜브 채널에서 함께 따라할 수 있습니다. 유튜브 채널도 확인해 주세요.

YouTube Video