TypeScript, 유니온 타입에서 타입 융합을 방지하는 방법

타입 융합이란, 예를들어 'red' | string 과 같은 타입의 경우 'red'string에 포함되는 타입이므로 결국 string 하나로 융합되는 것을 의미합니다. 이런 융합을 막기 위한 방법은 string 대신 string & {}을 사용하는 것입니다. 관련된 예제 코드는 다음과 같습니다.

// string & {} 를 교차(Intersection)시키면 타입 융합(Type Flattening)을 방지합니다.
type Color = 'red' | 'blue' | 'green' | (string & {});

function setColor(color: Color) {
  console.log(`Setting color to ${color}`);
}

setColor("red")
// 💡 효과:
// 1. setColor('') 입력 시 'red', 'blue', 'green' 팝업 자동완성이 뜹니다.
// 2. setColor('#123456') 처럼 임의의 문자열을 넣어도 타입 에러가 발생하지 않습니다.

TypeScript, 재귀 호출을 통한 타입 정의

타입스크립트는 타입 정의에서 재귀 호출이 가능합니다. 재귀 호출이 적용된 아래의 코드가 그 예입니다.

type Flatten<T> =
    T extends (infer U)[]
        ? Flatten<U>
        : T;

Flatten 타입을 정의하고 있는데, 재귀적으로 다시 Flatten을 호출하고 있습니다. 위의 Flatten 타입의 사용 예는 다음과 같습니다.

type A = Flatten<number[][][][]>; // number

위 코드 예시의 Flatten은 재귀적으로 다음처럼 수행하여 최종적인 number 타입을 정의하고 있습니다.

number[][][][] → number[][][] → number[][] → number[] → number

TypeScript, 문자열 패턴 매칭

다음과 같은 문자열 리터럴 타입이 있습니다.

type url = "user/profile";

위의 타입에서 "/" 문자 다음의 문자열인 "person"을 문자열 패턴 매칭을 통해 얻는 코드는 다음과 같습니다.

type Last<T> =
    T extends `${string}/${infer U}`
        ? U
        : never;

type A = Last<url>; // "profile"

TypeScript, 객체 타입의 키 값으로 구성된 Type과 키의 값으로 구성된 Type 정의

다음과 같은 객체가 있습니다.

type User = {
    name: "nameValue"
    age: "ageValue"
};

User 타입을 구성하는 키 값에 대한 타입은 "name" | "age"입니다. 이를 얻는 코드는 다음과 같습니다.

type KeysType<T extends object> = keyof T & string;
type KT = KeysType<User>; // "name" | "age"

이번에는 User 타입의 키에 대한 값에 대한 타입은 "nameValue" | "ageValue"입니다. 이를 얻는 코드는 다음과 같습니다.

type ValuesType<T extends object> = T[keyof T & string];
type VT = ValuesType<User>; // "nameValue" | "ageValue"

TypeScript, 타입으로써 {}object의 차이점

타입으로써 {}object를 구분하는 것은 타입스크립트 프로그래머로써 매우 매우 중요합니다.

먼저 {} 타입으로 정의된 변수 객체에는 nullundefined를 제외한 모든 것들을 할당할 수 있습니다. object 타입으로 정의된 변수 객체에는 원시타입 값을 제외한 모든 것들을 할당할 수 있습니다.

즉, object 타입으로 선언된 아래의 예제 코드를 참고하기 바랍니다.

let obj: object;

obj = {};
obj = [];
obj = new Date();
obj = () => {};
obj = /abc/;

obj = 10;          // 오류
obj = "hello";     // 오류
obj = true;        // 오류
obj = Symbol();    // 오류
obj = BigInt(10);  // 오류

{} 타입으로 선언된 아래의 예제 코드도 있습니다.

let x: {};

x = {};
x = [];
x = 10;
x = "hello";
x = true;
x = () => {};

x = null;          // 오류
x = undefined;     // 오류