타입 호환 Type Compatibility


<aside> 💡 자바스크립트는 객체 리터럴이나 익명 함수 등을 사용하기 때문에 명시적으로 타입을 지정하는 것보다 코드의 구조 관점에서 타입을 지정하는게 더 잘 어울릴 수도 있다.

</aside>

타입스크립트에서 다른 타입 간에 호환 여부를 점검하는 것을 타입 호환이라고 한다. 아래 Avengers 클래스는 Ironman 인터페이스를 상속받아 구현한 게 아닌데도 에러가 발생하지 않는다. 타입스크립트에선 타입에 정의되어 있는 속성의 타입을 가지고 코드가 호환되는지 확인하기 때문이다.

interface Ironman {
  name: string;
}

class Avengers {
  name: string;
}

let ironMan: Ironman;
ironMan = new Avengers(); // ok 타입 호환

구조적 타이핑 Structural typing


<aside> 💡 객체 속성, 함수 파라미터 등이 비교하는 대상보다 더 많다면 구조적으로 더 크다고 볼 수 있다.

</aside>

코드 구조 관점에서 타입이 서로 호환되는지 판단하는 것을 구조적 타이핑이라고 한다. 아래 예제에서 capt 객체와 Avengers 인터페이스 모두 name 속성이 있기 때문에 capthero 타입은 서로 호환된다. 더 엄밀하게 말하면 capt 객체 타입이 구조적으로 Avengers 보다 크기 때문에 hero에 할당(호환)될 수 있는 것.

interface Avengers {
  name: string;
}

let hero: Avengers;

const capt = { name: 'Captain', location: 'Seoul' };
hero = capt; // ok 타입 호환

함수 호출 역시 마찬가지다. capt 객체에 name 속성이 있으므로 assemble 함수의 인자로 넘길 수 있다.

function assemble(param: Avengers) {
  console.log(param.name);
}

assemble(capt); // 'Captain' (타입 호환)

타입 호환 예제


Interface / Class (객체 속성)

<aside> 💡 interface / class / 객체 등에서 할당 연산자의 右项이 구조적으로 더 크다면 타입은 호환될 수 있다.

</aside>

아래 developer = person 코드에서 오른쪽에 있는 person 타입을 developer에 할당하려고 하면 에러가 발생한다(타입 호환 불가). developer에서 필요한 skill 속성을 person이 가지고 있지 않기 때문이다. 즉, 구조적으로 더 작은 persondeveloper에 할당하려고 해서 발생하는 에러다.

interface Developer {
  name: string;
  skill: string;
}

interface Person {
  name: string;
}

let developer: Developer;
let person: Person;

developer = person; // Error! 타입 호환 불가
// TS2741: Property 'skill' is missing in type 'Person' but required in type 'Developer'.

person = developer; // ok 타입 호환

Person 인터페이스를 클래스로 바꿔도 결과는 동일하다. 타입스크립트에서 타입 호환을 검증할 때 내부에 존재하는 속성과 타입에 대해서만 비교한다. interface type class 등은 상관없다.