keyof
keyof 키워드는 object 타입의 모든 key 를 가져와서 유니온 타입으로 반환한다.
아래의 예시를 보자
interface Person {
age: number;
name: string;
}
type PersonKeys = keyof Person; // "age" | "name"
위에서 PersonKeys 타입은 age와 name 중 하나의 문자열 값만 가질 수 있는 리터럴 타입이다.
Mapped Types
Mapped Types 를 이용하면, 기존의 타입을 새로운 타입으로 변환할 수 있다.
object 의 각 속성에 대해 반복적으로 적용을 할 수 있어서
타입 변환 과정을 간결하게 만들어 준다.
type TypeChanger<MyType> = {
[Key in keyof MyType]: NewType;
};
위에서 MyType 은 변환하고자 하는 기존 타입이고,
Key는 MyType의 각 key에 대한 반복 변수이다.
그리고 NewType 은 key에 적용하고자 하는 새로운 타입이다.
적용한 예제를 살펴보자
type Car = {
color: boolean,
model: boolean,
price: boolean | number,
};
type TypeChanger<MyType> = {
[Key in keyof MyType]: string;
};
type NewCarType = TypeChanger<Car>;
let obj: NewCarType = {
color: 'red',
model: 'kia',
price: '300',
};
NewCarType은 Car 타입의 각 속성을 string 타입으로 바꾼 새로운 타입이다.
따라서 obj 라는 객체는 변환된 타입에 따라서 모든 속성이 string 타입을 가져야하게된다.
조건부 타입
여기서 말하고자 하는 조건부 타입은 삼항연산자와 유사하다.
아래의 형식을 보자
T extends U ? X : Y
T가 U에 속하는 타입이라면 X 타입을 반환, 아니라면 Y 타입을 반환한다.
결국, 입력 타입에 따라서 다른 타입을 동적으로 생성할 수 있도록 하기 위함이다.
type Age<T> = T extends string ? string : unknown;
위 코드에서 Age<T> 타입은 T가 string 타입을 확장하면 (* T가 string 타입이거나 string 을 포함하는 타입인 경우)
string을 반환하고, 그렇지 않으면 unknown 을 반환한다.
infer
infer 키워드는 조건부 타입과 함께 쓰일 수 있다.
주로 타입 내부의 구조에서 특정 부분을 추출하고자 할 때 사용된다.
type Person<T> = T extends infer R ? R : unknown;
type 새타입 = Person<string> // 새타입은 string 타입입니다
infer 우측에 자유롭게 작명해주면 타입을 T 에서 유추하여 R 이라는 변수에 집어넣는 것이다.
그래서 위의 예제의 경우 T 자리에 string 이 들어갔고, R 은 string 이 된다.
만약 array 안에 있는 타입이 어떤 타입인지 뽑아서 변수로 만들어줄 수도 있다.
아래의 예제를 보자
type 타입추출<T> = T extends (infer R)[] ? R : unknown;
type NewType = 타입추출< boolean[] > // NewType 은 boolean 타입입니다
위와 같이 (infer R)[] 처럼 작성하면
array 안에 있는 요소의 타입을 뽑아서 R 변수에 할당에 준다고 생각하면 된다.
ref: 코딩애플