애드블럭 종료 후 보실 수 있습니다.

ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • TypeScript 유틸리티 타입 소개
    JS & TS 2024. 10. 11. 14:38
    728x90

    TypeScript는 JavaScript에 정적 타입을 더하여 코드의 안정성을 높이는 역할을 합니다.
    특히 TypeScript에는 유용한 유틸리티 타입들이 있어, 코드를 작성할 때 매우 편리하게 활용할 수 있습니다.
    TypeScript에서 자주 사용되는 유틸리티 타입과 기능을 소개해 보겠습니다.

    1. Pick<Type, Keys>

    Pick은 특정 타입에서 원하는 프로퍼티만 선택하여 새 타입을 만드는 데 유용합니다.
    이 기능을 사용하면 큰 인터페이스나 객체 타입 중에서 필요한 부분만 사용하고 싶을 때 매우 편리합니다.

    언제 사용하나요?

    • 특정 객체에서 필요한 일부 속성만 타입으로 사용하고자 할 때

    사용 예시

    interface User {
      id: number;
      name: string;
      age: number;
      email: string;
    }
    
    // User 타입에서 id와 name만 포함한 새 타입을 생성
    type UserSummary = Pick<User, 'id' | 'name'>;
    
    const user: UserSummary = {
      id: 1,
      name: 'Alice',
    };

    2. Omit<Type, Keys>

    Omit은 특정 타입에서 원하는 프로퍼티를 제외하고 새 타입을 만드는 데 사용됩니다.
    Pick과는 반대로 작동하며, 타입에서 제외할 속성을 지정할 수 있습니다.

    언제 사용하나요?

    • 객체 타입에서 특정 프로퍼티만 제거하고 싶을 때

    사용 예시

    interface User {
      id: number;
      name: string;
      age: number;
      email: string;
    }
    
    // User 타입에서 email을 제외한 새 타입을 생성
    type UserWithoutEmail = Omit<User, 'email'>;
    
    const user: UserWithoutEmail = {
      id: 1,
      name: 'Alice',
      age: 25,
    };

    3. Partial

    Partial은 특정 타입의 모든 프로퍼티를 선택적으로 만듭니다.
    주로 객체의 일부만 업데이트할 때 유용합니다.

    언제 사용하나요?

    • 객체를 부분적으로 업데이트하거나 초기 값을 설정할 때

    사용 예시

    interface User {
      id: number;
      name: string;
      age: number;
      email: string;
    };
    
    type OptionalUser = Partial<User>
    
    // 모든 속성이 선택적임
    const updateUser: OptionalUser = {
      name: 'Bob',
    };

    4. Required

    Required는 특정 타입의 모든 프로퍼티를 필수로 만듭니다.
    Partial의 반대 기능을 한다고 볼 수 있습니다.

    언제 사용하나요?

    • 객체의 모든 속성이 반드시 필요할 때

    사용 예시

    interface User {
      id?: number;
      name?: string;
      age?: number;
    }
    
    // 모든 속성이 필수로 바뀜
    type CompleteUser = Required<User>;

    5. Readonly

    Readonly는 특정 타입의 모든 프로퍼티를 읽기 전용으로 만듭니다.
    이 타입을 사용하면 객체의 속성을 변경할 수 없도록 제한할 수 있습니다.

    언제 사용하나요?

    • 객체의 불변성을 유지하고 싶을 때

    사용 예시

    interface User {
      id: number;
      name: string;
    }
    
    const user: Readonly<User> = {
      id: 1,
      name: 'Alice',
    };
    
    // user.id = 2; // 오류 발생: 읽기 전용 속성입니다.

    6. Record<Keys, Type>

    Record는 키와 값을 정의하여 새로운 타입을 생성합니다.
    주로 객체를 미리 정의된 키의 집합으로 관리하고 싶을 때 사용합니다.

    언제 사용하나요?

    • 특정 키 집합과 그 값의 타입을 명확하게 정의하고 싶을 때

    사용 예시

    type CatInfo = { age: number; breed: string; };
    type CatName = 'miffy' | 'boris' | 'mordred';
    
    const cats: Record<CatName, CatInfo> = {
      miffy: { age: 10, breed: 'Persian' },
      boris: { age: 5, breed: 'Maine Coon' },
      mordred: { age: 16, breed: 'British Shorthair' }
    };

    7. Exclude<Type, ExcludedUnion>

    Exclude는 특정 타입에서 다른 타입을 제거하여 새 타입을 만듭니다.

    언제 사용하나요?

    • 유니온 타입에서 특정 타입을 제외하고 싶을 때

    사용 예시

    type Status = 'active' | 'inactive' | 'banned';
    
    type ActiveStatus = Exclude<Status, 'banned'>;
    
    const status: ActiveStatus = 'active';

    8. Extract<Type, Union>

    Extract는 특정 타입에서 지정된 타입만 추출합니다.

    언제 사용하나요?

    • 유니온 타입에서 특정 타입만 선택하고 싶을 때

    사용 예시

    type Status = 'active' | 'inactive' | 'banned';
    
    type AllowedStatus = Extract<Status, 'active' | 'inactive'>;
    
    const status: AllowedStatus = 'inactive';

    9. NonNullable

    NonNullable은 특정 타입에서 nullundefined를 제거합니다.

    언제 사용하나요?

    • 타입에서 null 또는 undefined를 허용하지 않도록 하고 싶을 때

    사용 예시

    type User = {
      name: string | null;
      age?: number;
    };
    
    type NonNullableUser = NonNullable<User['name']>; // string 타입만 남음

    10. ReturnType

    ReturnType은 함수 타입의 반환 타입을 추출합니다.
    주로 함수의 반환 타입을 다른 곳에서 재사용하고자 할 때 유용합니다.

    언제 사용하나요?

    • 함수의 반환 타입을 따로 관리하거나 재사용하고 싶을 때

    사용 예시

    function getUser() {
      return {
        id: 1,
        name: 'Alice',
      };
    }
    
    type User = ReturnType<typeof getUser>;
    
    const user: User = {
      id: 1,
      name: 'Alice',
    };

    11. Parameters

    Parameters는 함수 타입의 매개변수 타입을 튜플로 반환합니다.

    언제 사용하나요?

    • 함수의 매개변수 타입을 다른 함수에서 재사용하고 싶을 때

    사용 예시

    function add(a: number, b: number): number {
      return a + b;
    }
    
    type AddParams = Parameters<typeof add>; // [number, number]
    
    const args: AddParams = [3, 5];
    const result = add(...args);

    커스텀 유틸리티 타입

    내장된 유틸리티 타입 외에도 자주 사용하는 커스텀 유틸리티 타입들이 있습니다.
    다섯 가지 유용한 커스텀 유틸리티 타입을 소개합니다.

    1. Mutable

    Readonly의 반대로, 특정 타입의 모든 프로퍼티를 변경 가능하게 만듭니다.

    언제 사용하나요?

    • 읽기 전용 타입을 다시 변경 가능하게 하고 싶을 때

    사용 예시

    type Mutable<T> = {
      -readonly [P in keyof T]: T[P];
    };
    
    interface ReadonlyUser {
      readonly id: number;
      readonly name: string;
    }
    
    type MutableUser = Mutable<ReadonlyUser>;
    
    const user: MutableUser = {
      id: 1,
      name: 'Alice',
    };
    
    user.id = 2; // 정상적으로 동작

    2. Nullable

    특정 타입에 null을 추가하여 허용하는 타입을 만듭니다.

    언제 사용하나요?

    • 기존 타입에 null을 허용하고 싶을 때

    사용 예시

    type Nullable<T> = T | null;
    
    interface User {
      id: number;
      name: string;
    }
    
    type NullableUser = Nullable<User>;
    
    const user: NullableUser = null; // 정상적으로 동작

    3. OptionalKeys

    특정 타입에서 선택적(?)인 프로퍼티의 키만 추출합니다.

    언제 사용하나요?

    • 객체 타입에서 선택적인 프로퍼티만 추출하고 싶을 때

    사용 예시

    type User = {
      id: number;
      name?: string;
      age?: number;
    };
    
    type OptionalKeys<T> = {
      [K in keyof T]-?: undefined extends T[K] ? K : never;
    }[keyof T];
    
    type UserOptionalKeys = OptionalKeys<User>; // 'name' | 'age'

    4. UnionToIntersection

    유니온 타입을 인터섹션 타입으로 변환합니다.

    언제 사용하나요?

    • 여러 타입을 결합하여 하나의 타입으로 만들고 싶을 때

    사용 예시

    type UnionToIntersection<U> = (U extends any ? (arg: U) => void : never) extends (arg: infer I) => void ? I : never;
    
    type Union = { a: string } | { b: number };
    
    type Intersection = UnionToIntersection<Union>; // { a: string } & { b: number }

    5. DeepPartial

    모든 중첩된 프로퍼티를 선택적으로 만듭니다.

    언제 사용하나요?

    • 깊은 객체 구조에서 모든 속성을 선택적으로 만들고 싶을 때

    사용 예시

    type DeepPartial<T> = {
      [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
    };
    
    interface User {
      id: number;
      profile: {
        name: string;
        age: number;
      };
    }
    
    type PartialUser = DeepPartial<User>;
    
    const user: PartialUser = {
      profile: {
        name: 'Alice',
      },
    };

     

    이처럼 TypeScript의 다양한 유틸리티 타입들과 인터페이스 관련 기능들을 사용하면 코드의 가독성과 재사용성을 높이고, 타입 안전성을 강화할 수 있습니다.
    Typescript의 유틸리티 타입들을 적극 활용하고, 커스텀 유틸리티 타입을 만들어 더욱 안정적이고 유지보수가 쉬운 코드를 작성해 보세요.

    댓글

Designed by Tistory.