티스토리 뷰

 

타입스크립트는 정적 타입 검사 기능 외에도 다양하고 유용한 기능들을 제공합니다. 하지만 많은 개발자들이 이러한 기능들을 잘 모르고 사용하지 않는 경우가 많습니다.

 

해당 글에서는 타입과 관련된 다양한 유틸리티 기능들을 살펴보도록 하겠습니다.

 

유틸리티 타입 (Utility Types)

타입스크립트는 타입 보장 및 검사 기능 뿐만 아니라 그와 관련된 다양한 유틸리티 타입을 제공하여 기존 타입을 기반으로 새로운 타입을 쉽게 만들 수 있도록 도와줍니다.

 

쉽게 말하자면 마치 레고 블럭처럼, 타입스크립트에서는 이미 존재하는 타입들을 조립해서 새로운 타입을 만들 수 있는 편리한 도구들을 제공하는데, 이걸 "유틸리티 타입"이라고 부릅니다.

 

여기에선 몇 가지 자주 그리고 널리 사용되는 유틸리티 타입들을 소개하겠습니다.

 

Partial<T>

제네릭 T의 모든 속성을 선택적으로 만듭니다. 객체의 일부 속성만 업데이트할 때 유용합니다.

interface User {
    name: string;
    age: number;
    email?: string;
}

const partialUser: Partial<User> = { age: 30 };

 

Required<T>

제네릭 T의 모든 속성을 필수로 만듭니다, 따라서 필수적으로 모든 속성의 값들을 정의해야 합니다.

const requiredUser: Required<User> = {
    name: "Dev Ttangkong",
    age: 20,
    email: "helloworld@example.com"
};

 

Readonly<T>

제네릭 T의 모든 속성을 읽기 전용으로 만듭니다, 따라서 모든 속성 값들은 참조만 가능하고 정의할 수는 없습니다.

const readonlyUser: Readonly<User> = {
    name: "John",
    age: 30,
};

// Error: Cannot assign to 'age' because it is a read-only property.
readonlyUser.age = 31;

 

Pick<T, K>

제네릭 T 타입에서 K 속성만 선택하여 새로운 타입을 만듭니다.

type UserNameAndAge = Pick<User, "name" | "age">;

 

Omit<T, K>

제네릭 T 타입에서 K 속성을 제외한 새로운 타입을 만듭니다.

type UserWithoutEmail = Omit<User, "email">;

 

조건부 타입 (Conditional Types)

"타입"스크립트라는 이름에 걸맞게, 단순한 타입을 정의하는 것을 넘어 조건까지 추가하여 코드를 더욱 정교하고 안전하게 만들 수 있다는 사실 혹시 알고 계셨나요? 조건부 타입을 사용하면 코드의 의도를 명확하게 전달하고 오류를 예방할 수 있습니다.

 

먼저 조건부 타입은 삼항 연산자처럼 비슷하게 작동합니다. 입력된 제네릭 타입에 따라 조건을 검사하고, 참이면 좌측 타입, 거짓이면 우측 타입을 반환합니다.

 

type IsString<T> = T extends string ? string : number;

 

예를 들어, 앞서 설명한 문법을 인지하고 해당 코드를 보면 제네릭 T가 string인지 number인지에 따라 반환되는 타입을 결정하는 타입이라는 것을 볼 수 있습니다.

 

조건부 타입은 단순히 타입을 결정하는 것뿐만 아니라, 유니온 타입(Union Types) 개념과 함께라면 더욱 유연성 있는 기능을 제공해줄 수 있습니다. 예를 들어, 다음 코드는 T가 string 또는 number 배열인 경우 해당 요소 타입을 반환합니다.

 

type ArrayElementType<T> = T extends Array<string> ? string : T extends Array<number> ? number : never;

 

따라서 해당 경우는 주어진 배열의 요소가 문자열인지 숫자인지를 반환합니다, 이런 코드를 어떻게 활용할 수 있는 지 알아 보도록 하겠습니다.

 

type ArrayElementType<T> = T extends Array<string> ? string : T extends Array<number> ? number : never;
const values = [
    "Hello world!",
    "니코니코니~",
    "오니짱~",
];

function test(value: ArrayElementType<typeof values>) {
    console.log(value);
}

// 'number' 형식의 인수는 'string' 형식의 매개 변수에 할당될 수 없습니다.ts(2345)
test(1);

 

해당 코드를 보면 values의 타입이 string[] 즉 문자열 배열이라면 인자는 string을 받는다라는 의미가 될 것입니다, 예를 들어, ["Hello", "World"]와 같은 문자열 배열을 정의하면 문자열을, [1, 2, 3]과 같은 숫자 배열을 정의하면 숫자로 타입이 추론될 것입니다.

 

모든 상황에서 앞서 설명드린 기능들이 항상 유용하지는 않겠지만 알고 있다고 해서 나쁜 것은 없다고 생각합니다, 해당 글을 읽어주셔서 감사드립니다.

 

Happy coding in the another world!