extends 는 typescript 에서 다양하게 사용이 가능합니다. 크게 아래와 같은 용도로 사용 됩니다.
타입의 확장
이름 그대로 interface 를 확장하고 싶을때 사용이 가능합니다. type 의 intersection(&) 문법과 동일한 기능입니다.
Copy 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 함수의 인자 처럼 제너릭 타입을 제한 할수 있습니다.
Copy 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 의 역할을 하기도 합니다.
Copy 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 키워드를 통해 타입을 추론 할 수 있습니다.
Copy 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 이 라고 해석할 수 있습니다.