Reference DOCS

타입호환성

Untitled

<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**를 받아들이기 때문에 여전히 할당 가능합니다.