Extends
extends 는 typescript 에서 다양하게 사용이 가능합니다. 크게 아래와 같은 용도로 사용 됩니다.
- 확장
- 제한
- 조건부
- 추론 (with Infer)
타입의 확장
이름 그대로 interface 를 확장하고 싶을때 사용이 가능합니다. type 의 intersection(&) 문법과 동일한 기능입니다.
type Profile = { name: string; age: number }
type DogProfile = Profile & { breed: 'Bulldog' | 'Poodle' };
// DogProfile { name: string; age:number; breed: 'Bulldog' | 'Poodle' }
interface DogProfile extends Profile {
breed: 'Bulldog' | 'Poodle'
}
// DogProfile { name: string; age:number; breed: 'Bulldog' | 'Poodle' }
Generic 의 타입 제한 하기
ts 함수의 인자 처럼 제너릭 타입을 제한 할수 있습니다.
type MessageOf<T> = T["message"];
// Type Error: Type '"message"' cannot be used to index type 'T'.
type MessageOf<T extends { message: unknown }> = T["message"];
type Email = { message: string; }
type Chat = { text: string; }
type EmailMessage = MessageOf<Email>
type Email = MessageOf<Chat> // Type Error
위의 예시에서 첫번째 MessageOf 을 확인해 봅시다. 제너릭 T 의 타입은 정해지지 않았습니다. 따라서, property 에 message 가 없을 수 도 있기 때문에 에러가 발생 합니다.
두번째 MessageOf 같은 경우는 extends 로 타입을 제한합니다. message property 를 가진 타입만 제너릭으로 들어올 수 있으므로, Error 가 발생하지 않습니다.
반대로 제너릭을 사용할 때 옳지 않은 타입을 넘겨주면 Type Error 가 발생합니다.
조건부 타입
extends 는 많은 언어가 포함하고 있는 if 의 역할을 하기도 합니다.
type Example = "A" extends string ? "STRING" : "UNKNOWN"; // "STRING"
// 제너릭에서 사용이 가능합니다.
type MessageOf<T> = T extends { message: unknown } ? T["message"] : never;
interface Email { message: string; }
interface Dog { bark(): void; }
type EmailMessageContents = MessageOf<Email>; // string
type DogMessageContents = MessageOf<Dog>; // never
// 중첩도 가능 합니다.
type TypeOf<T> = T extends string
? 'string'
: T extends number
? 'number'
: T extends boolean
? 'boolean'
: 'unknown'
type StrType = TypeOf<string> // "string"
type StrType = TypeOf<number> // "string"
type StrType = TypeOf<Function> // "unknown"
타입 추론 Infer
아래와 같은 타입이 있다고 가정해봅시다. 우리는 때로 'User' 타입이 필요할 수 있습니다. 그럴땐 infer 키워드를 통해 타입을 추론 할 수 있습니다.
const userList = [{ name: 'John' }] // type: Array<User>
type ItemOf<T> = T extends Array<infer U> ? U : unknown;
type User = ItemOf<typeof userList>; // User { name: string }
위에서 infer U 는 추론하고자 하는 타입을 의미합니다. 위의 ItemOf 를 문맥 그대로 해석해 봅시다.
제너릭 T 가 Array<추론하고자 하는 타입>
타입의 형태를 하고 있다면 ItemOf 의 반환 타입은 추론하고자 하는 타입이고, 아니면 unknown 이 라고 해석할 수 있습니다.