구조적 타이핑

Kaia·2023년 8월 28일
post-thumbnail

💡 토스테크블로그 내 "타입 호환성" 관련 아티클을 읽고 이해하고 작성한 글입니다!

타입스크립트의 타입 호환성은 구조적 서브타이핑을 기반으로 한다.

구조적 타이핑은 오직 멤버만으로 타입을 관계시키는 방법으로, 명목적 타이핑과는 대조적이다.

즉, 구조적 타이핑 규칙 하에

y가 최소한 x와 동일한 멤버를 가지고 있다면 x와 y는 호환된다.

그에 앞서, 타입스크립트는 강한 타입시스템을 통해 높은 안정성과 품질, 가독성을 지향한다. 근데 왜 타입 호환성을 지향하지? 위의 장점들은 결여 되는 것 아닌가?

type Food = {
  /** 각 영양소에 대한 gram 중량값 */
  protein: number;
  carbohydrates: number;
  fat: number;
}

// food를 인자로 받아, calorie를 반환하는 함수
function calculateCalorie(food: Food){
  return food.protein * 4
    + food.carbohydrates * 4
    + food.fat * 9
}

만약 위와 같이 food를 인자로 받아, calorie를 반환하는 함수에서 실수 또는 의도를 가지고 food 대신 다른 인자를 넣었다고 가정해보자.

이 경우에 타입체커는 어떻게 타입을 판단하는 것이 좋을까?

만약 1번이라면 오류 없이 정상동작할 것이고, 2번과 같이 푸드와 다른 타입이며 칼로리 계산이 불가능한경우 오류로 판단할 것이다.

그렇다면 3번은?

type Burger = Food & {
  /** 햄버거 브랜드 이름 */
  burgerBrand: string;
}

위 코드와 같이 푸드타입을 가지며 칼로리 계산에 필요한 모든 프로퍼티를 포함하고 있어 런타임 상에서 정상적으로 동작한다면? 타입오류로 판단하는게 맞을까요?

위와 같은 케이스로 미루어볼때, 실제 정상적으로 동작할 수 있는 올바른 코드라면 타입 호환성을 지원하는게 더 좋을 수 있다. 그리고 이러한 유연성을 위해 타입스크립트의 타입시스템은 부분적으로 타입 호환을 지원하고 있다!

그렇지만, 타입 안정성까지 해치며 타입 호환을 지원하는 것은 바람직하지 않다.

이를 위해서 어떤 경우에 호환을 허용할건지 명확한 규칙이 필요하고 이에 따라 명목적 서브타이핑, 구조적 서브타이핑으로 구분된다.

명목적 타이핑은 타입 정의시에 상속관계임을 명확히 명시한 경우에만 타입호환을 호환한다.

  • 타입오류가 발생할 가능성을 제거하고 개발자의 명확한 의도 반영
/** 상속 관계 명시 */
type Burger = ***Food*** & {
  burgerBrand: string;
}

const burger: Burger = {
  protein: 29,
  carbohydrates: 48,
  fat: 13,
  burgerBrand: '버거킹'
}

const calorie = calculateCalorie(burger)
/** 타입검사결과 : 오류없음 (OK) */

자바, C#에서 명목적 서브 타이핑만 허용

구조적 서브타이핑은 상속관계가 명시 되어있지 않더라도 객체의 프로퍼티를 기반으로, 사용처에서 사용하는것에 문제가 없다면 타입 호환을 허용한다.

const burger = {
  protein: 29,
  carbohydrates: 48,
  fat: 13,
  burgerBrand: '버거킹'
}

const calorie = calculateCalorie(burger)
/** 타입검사결과 : 오류없음 (OK) */

타입스크립트 타입체커는 구조적 서브타이핑을 지원한다.

0개의 댓글