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;     // 오류

TypeScript, 메타 프로그래밍 …

TypeScript는 코드에 대한 코드 작성을 목적으로 하는 메타 프로그래밍 언어입니다. 현존하는 대다수의 거의 대부분의 프로그래밍 언어가 메타 프로그래밍이 가능하지만, 특히 TypeScript는 코드에서 타입을 자동으로 새롭게 재정의가 가능하다는 점에서 다른 프로그래밍 언어보다 조금은 더 메타 프로그래밍 언어적이라고 할 수 있습니다.

타입스크립트에서 메타 프로그래밍을 위해 제공하는 기능은 Generic, keyof, typeof, Conditional Types, Mapped Types, Template Literal Types 등이 있고 서브셋은 JavaScript의 메타 프로그래밍 기능인 Proxy, Reflect, Decorator(제안), Object.defineProperty() 등입니다. 타입스크립트에 한정하여 볼때 아래는 메타 프로그래밍을 위해 제공하는 아래의 예제 코드입니다.

// Generic
type Box<T> = { value: T };

// keyof
type Keys = keyof T;

// typeof
type T = typeof value;

// Indexed Access Type
type Value = T[K];

// Mapped Type
type Readonly<T> = {
    readonly [K in keyof T]: T[K];
};

// Conditional Type
type Result<T> = T extends string ? number : boolean;

// Template Literal Type
type Event<T extends string> = `${T}Changed`;

// infer
type Return<T> = T extends (...args: any[]) => infer R ? R : never;