타입스크립트는 숫자와 문자열 기반의 열거형을 제공한다.
enum Direction {
Up = 1,
Down,
Left,
Right,
}
Up
이 1로 초기화되면 뒤에 따라오는 멤버들은 2부터 차례대로 증가되는 값을 가진다.
초기화를 하지 않는다면 Up
은 0부터 시작해서 다음 멤버들은 1부터 증가되는 값을 가진다.
enum Direction {
Up = "UP",
Down = "DOWN",
Left = "LEFT",
Right = "RIGHT",
}
문자열 열거형은 각 멤버를 초기화해야하며, 자동 증가 기능이 없지만 직렬화에서 이점을 가진다.
예를 들어 숫자만으로 이것이 어떤 의미인지 정보를 제공받기 어렵지만, 문자열 열거형을 이용하면 코드를 실행할 때 유의미하고 읽기 좋은 값을 이용하여 실행할 수 있다.
재사용이 가능한 컴포넌트를 생성하는 주요 도구 중 하나가 제네릭이다.
제네릭을 사용해서 단일타입이 아닌 다양한 타입에서 작동하는 컴포넌트를 작성할 수 있기 때문이다.
function identity<T>(arg: T): T {
return arg;
}
T
는 유저가 준 인수의 타입을 캡처하고 이 정보를 나중에 사용할 수 있게 한다.
위 예제는 T
를 반환타입으로 다시 사용하여 타입 정보를 함수의 한쪽에서 다른 한쪽으로 운반할 수 있게끔 했다.
T
대신 any
를 사용해도 코드에는 오류가 없지만, 타입 정보를 잃는 손해가 발생한다.
반면 제네릭은 어떤 정보도 잃지 않을 수 있다.
function loggingIdentity<T>(arg: T): T {
console.log(arg.length);
return arg;
}
인수의 타입이 문자열이 아니기 때문에 length
프로퍼티는 존재하지 않고 오류가 발생된다.
특정 타입으로 동작하는 제네릭 함수를 만들어 보자.
제네릭 타입이지만 length
프로퍼티를 가지는 타입을 원할 때 제네릭이 어떤 타입이 될 수 있는 지 제약 조건을 나열해줄 수 있다.
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length);
return arg;
}
T
는 인터페이스 규약을 따른다면 length
프로퍼티가 있어야 하며 이는 number
값을 가져야 한다.
따라서 T타입의 인수는 .length
를 사용해서 길이를 얻을 수 있게 되는 것이다.
만약 loggingIdentity(3);
명령을 주면 number
는 length
프로퍼티가 없으므로 오류가 발생한다.
function getProperty<T, K extends keyof T>(obj: T, key: K) {
return obj[key];
}
let x = { a: 1, b: 2, c: 3, d: 4 };
getProperty(x, "a");
getProperty(x, "m");
K는 T의 key로 제약되어 있다.
따라서 m
은 x
라는 객체에 존재하지 않는 키이기 때문에 오류가 발생한다.
반면 a
는 존재하는 키이기 때문에 정상동작한다.