nest.js

TypeScript Generics, Typescript-utility (2024.05.30)

goblin- 2024. 5. 30. 14:55

TypeScript Generics

Generics란?

  • Generics는 함수, 클래스, 인터페이스에서 사용할 수 있는 타입 변수를 정의합니다.
  • 코드의 재사용성을 높이고 타입을 안전하게 유지할 수 있도록 도와줍니다.

Generics의 사용 예시

1. 함수에서의 사용

function identity<T>(arg: T): T {
    return arg;
}

let output1 = identity<string>("Hello World");
let output2 = identity<number>(42);

console.log(output1); // "Hello World"
console.log(output2); // 42

 

  • identity 함수는 제네릭 타입 변수 T를 사용하여 입력과 출력의 타입을 동일하게 유지합니다.
  • identity<string> 문자열을 입력받아 반환하고, identity<number> 숫자를 입력받아 반환합니다.

2. 클래스에서의 사용

class GenericNumber<T> {
    zeroValue: T;
    add: (x: T, y: T) => T;
}

let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = (x, y) => x + y;

console.log(myGenericNumber.add(myGenericNumber.zeroValue, 5)); // 5
  • GenericNumber 클래스는 제네릭 타입 변수 T를 사용하여 숫자형 데이터를 처리합니다.
  • zeroValue add 메서드는 타입 T 기반으로 합니다.

3. 인터페이스에서의 사용

interface KeyValuePair<K, V> {
    key: K;
    value: V;
}

let kvp: KeyValuePair<string, number> = { key: "age", value: 30 };

console.log(kvp.key); // "age"
console.log(kvp.value); // 30
  • KeyValuePair 인터페이스는 두 개의 제네릭 타입 변수 KV를 사용하여 키-값 쌍을 정의합니다.
  • kvp 객체는 문자열 키와 숫자 값을 가집니다.

 

 

TypeScript Utility Types

Utility Types란?

  • TypeScript는 여러 유용한 유틸리티 타입을 제공하여 기존 타입을 변환하거나 조작할 수 있습니다.
  • 유틸리티 타입은 주로 기존 타입에서 부분적으로 변경하거나 일부를 선택하여 새로운 타입을 만드는 데 사용됩니다.

주요 유틸리티 타입과 예시

1. Partial<T>

  • 모든 프로퍼티를 선택적으로 만드는 타입입니다.
interface User {
    name: string;
    age: number;
    email: string;
}

let partialUser: Partial<User> = {
    name: "John"
};

console.log(partialUser); // { name: "John" }
  • Partial<User> 타입은 User 인터페이스의 모든 프로퍼티를 선택적으로 만듭니다.

 

2. Required<T>

  • 모든 프로퍼티를 필수적으로 만드는 타입입니다.
interface User {
    name?: string;
    age?: number;
    email?: string;
}

let user: Required<User> = {
    name: "John",
    age: 30,
    email: "john@example.com"
};

console.log(user); // { name: "John", age: 30, email: "john@example.com" }
  • Required<User> 타입은 User 인터페이스의 모든 프로퍼티를 필수적으로 만듭니다.

3. Readonly<T>

  • 모든 프로퍼티를 읽기 전용으로 만드는 타입입니다.
interface User {
    name: string;
    age: number;
    email: string;
}

let readonlyUser: Readonly<User> = {
    name: "John",
    age: 30,
    email: "john@example.com"
};

// readonlyUser.age = 31; // 오류: 'age'은 읽기 전용 프로퍼티입니다.
console.log(readonlyUser); // { name: "John", age: 30, email: "john@example.com" }
  • Readonly<User> 타입은 User 인터페이스의 모든 프로퍼티를 읽기 전용으로 만듭니다.

4. Pick<T, K>

  • 특정 프로퍼티만 선택하여 새로운 타입을 만드는 타입입니다.
interface User {
    name: string;
    age: number;
    email: string;
}

let pickedUser: Pick<User, "name" | "email"> = {
    name: "John",
    email: "john@example.com"
};

console.log(pickedUser); // { name: "John", email: "john@example.com" }
  • Pick<User, "name" | "email"> 타입은 User 인터페이스에서 nameemail 프로퍼티만 선택하여 새로운 타입을 만듭니다.

5. Omit<T, K>

  • 특정 프로퍼티를 제외하여 새로운 타입을 만드는 타입입니다.
interface User {
    name: string;
    age: number;
    email: string;
}

let omittedUser: Omit<User, "age"> = {
    name: "John",
    email: "john@example.com"
};

console.log(omittedUser); // { name: "John", email: "john@example.com" }

 

  • Omit<User, "age"> 타입은 User 인터페이스에서 age 프로퍼티를 제외하여 새로운 타입을 만듭니다.

 

6. Record 타입

  • Record 타입은 객체의 키와 값의 타입을 지정할 있게 해주는 유틸리티 타입입니다.
type User = {
  id: number;
  name: string;
};

type UserRecord = Record<number, User>;

const users: UserRecord = {
  1: { id: 1, name: "John" },
  2: { id: 2, name: "Jane" },
  3: { id: 3, name: "Jim" },
};

console.log(users[1]); // { id: 1, name: "John" }
  • 이 예시에서 UserRecordnumber 타입의 키를 가지며, 각 키에 매핑된 값은 User 타입입니다.

7. 유니온 타입

  • 유니온 타입은 변수나 매개변수가 여러 타입 하나일 있음을 나타냅니다.
let value: number | string;
value = 42;        // OK
value = "Hello";   // OK
// value = true;  // Error: Type 'boolean' is not assignable to type 'number | string'.
  • value 변수는 number 또는 string 타입을 가질 수 있습니다.

객체의 키들로 유니온 타입 만들기

  • 객체의 키들로 유니온 타입을 만드는 것은 매우 유용합니다. 이는 TypeScript 키워드 keyof 사용하여 가능합니다.
type User = {
  id: number;
  name: string;
  email: string;
};

type UserKeys = keyof User;  // 'id' | 'name' | 'email'

let key: UserKeys;
key = "id";       // OK
key = "name";     // OK
key = "email";    // OK
// key = "age";   // Error: Type '"age"' is not assignable to type 'UserKeys'.

 

 

요약

  • Generics는 함수, 클래스, 인터페이스에서 타입 변수를 정의하여 코드의 재사용성을 높이고 타입 안전성을 유지합니다.
  • Utility Types 기존 타입을 변환하거나 조작하여 새로운 타입을 만드는 사용됩니다. 주요 유틸리티 타입에는 Partial, Required, Readonly, Pick, Omit 등이 있습니다.