
<aside> 👩🌾 TypeScript의 타입 호환성은 **구조적 서브 타이핑(subtyping)**을 기반으로 합니다. 구조적 타이핑이란 오직 멤버만으로 타입을 관계시키는 방식입니다. 명목적 타이핑(nominal typing) 과는 대조적입니다.
</aside>
interface Named {
name: string;
}
let x: Named;
// y의 추론된 타입은 { name: string; location: string; } 입니다.
let y = { name: "Alice", location: "Seattle" };
x = y; //⭕️
y = x; //❌
x에 y를 할당할 수 있음 !
→ y는 name이라는 문자열 멤버를 가졌기에 할당 가능
y는 x에 할당할 수 없음
→ name, location 멤버를 가져야함
<aside> 👩🌾 호출하는 측에서 더 특수한 타입을 취하여 함수를 제공할 수 있을 뿐만 아니라, 덜 특수화된 타입의 함수를 호출할 수 있게 함
</aside>
양방향 호환
enum EventType {
Mouse,
Keyboard,
}
interface Event {
timestamp: number;
}
interface MyMouseEvent extends Event {
x: number;
y: number;
}
// 바람직하진 않지만 유용하고 일반적임
listenEvent(EventType.Mouse, (e: MyMouseEvent) => console.log(e.x + "," + e.y));
여기서 전달되는 핸들러는 (e: MyMouseEvent) => void 타입을 가집니다. 이 핸들러는 **MyMouseEvent**를 받아들이기 때문에 **Event**를 받아들이는 (n: Event) => void 타입에 할당 가능합니다.
// 건전성 측면에서 바람직하지 않은 대안
listenEvent(EventType.Mouse, (e: Event) =>
console.log((e as MyMouseEvent).x + "," + (e as MyMouseEvent).y)
);
listenEvent(EventType.Mouse, ((e: MyMouseEvent) =>
console.log(e.x + "," + e.y)) as (e: Event) => void);
여기서도 전달되는 핸들러는 (e: Event) => void 타입을 가집니다. 이 핸들러는 **MyMouseEvent**를 받아들이지만, 명시적으로 형변환을 통해 **Event**를 받아들이기 때문에 여전히 할당 가능합니다.