구조적 타이핑(신선도)

Kaia·2023년 8월 28일
post-thumbnail

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

타입스크립트 타입 체커가 타입호환을 지원하는 것으로 공부했다.

그런데…

const calorie = calculateCalorie({
  protein: 29,
  carbohydrates: 48,
  fat: 13,
  burgerBrand: '버거킹'
})
/** 타임검사결과 : 오류 (NOT OK)*/

이게 무슨 일일까?

우선 타입스크립트 컴파일러가 동작하는 방식에 대해 다시 살펴보자.

[1-1] Typescript

타입스크립트 컴파일러의 역할은 ts 소스코드를 AST로 변환한 뒤, 타입검사를 수행하고, 그 후 js 소스코드로 변환하는 과정을 담당한다.

ts소스 코드를 AST로 변환하는 과정은 scanner.ts, parser.ts에서

타입 검사는 binder.ts, checker.ts에서

js 소스코드로 변환하는 과정은 emitter.ts, transformer.ts에서 담당한다.

이 중 구조적 타이핑과 타입 호환에 관한 부분은 타입검사와 연관이 있는 checker.ts 파일의 hasExcessProperties()

/** 함수 매개변수에 전달된 값이 FreshLiteral인 경우 true가 됩니다. */
const isPerformingExcessPropertyChecks =
    getObjectFlags(source) & ObjectFlags.FreshLiteral;

if (isPerformingExcessPropertyChecks) {
    /** 이 경우 아래 로직이 실행되는데,
     * hasExcessProperties() 함수는
     * excess property가 있는 경우 에러를 반환하게 됩니다.
     * 즉, property가 정확히 일치하는 경우만 허용하는 것으로
     * 타입 호환을 허용하지 않는 것과 같은 의미입니다. */
    if (hasExcessProperties(source as FreshObjectLiteralType)) {
        reportError();
    }
}
/**
 * FreshLiteral이 아닌 경우 위 분기를 skip하게 되며,
 * 타입 호환을 허용하게 됩니다. */

즉, fresh literal의 경우에는 타입호환의 예외가 발생한다.

  • 신선도 freshness 모든 객체리터럴은 초기에 ‘fresh’하며 타입단언을 하거나 타입 추론에 의해 obj literal의 타입이 확장되면 신선도가 사라진다. 특정한 변수에 object literal 을 할당하는 경우에는 위 2가지 중 한가지가 발생하므로 신선도가 사라지고, 함수에 인자로 바로 object literal을 전달하는 경우에는 신선도 유지 상태로 전달된다. 신선도(Freshness)

Strict object literal assignment checking by ahejlsberg · Pull Request #3823 · microsoft/TypeScript

위 논의에서 결정된 사항으로 fresh obj는 예외적으로 호환을 허용하지 않는데,

그 이유로는

/** 부작용 1
 * 코드를 읽는 다른 개발자가 calculateCalorie 함수가
 * burgerBrand를 사용한다고 오해할 수 있음 */
const calorie1 = calculateCalorie({
  protein: 29,
  carbohydrates: 48,
  fat: 13,
  burgerBrand: '버거킹'
})

/** 부작용 2
 * birgerBrand 라는 오타가 발생하더라도
 * excess property이기 때문에 호환에 의해 오류가
 * 발견되지 않음 */
const calorie2 = calculateCalorie({
  protein: 29,
  carbohydrates: 48,
  fat: 13,
  birgerBrand: '버거킹'
})

또, 특정 변수에 할당하지 않았으므로 어차피 해당 함수에서만 사용하고 다른데서는 사용되지 않는다. 이 경우 유연함보다 부작용 가능성이 높음. 굳이 사용 x

(그럼에도 사용하고자 한다면 [x: string]: any 등으로 명시적 허용)

결론적으로

타입스크립트 타입체커는 구조적 서브타이핑을 기반으로 타입 호환을 판단하되, Freshness에 따라 예외를 둔다.

프로그래밍 언어마다 타입검사가 동작하는 방식이 다르며, 이는 언어를 개발한 커뮤니티의 논의와 의사결정에 따라 선택된 결과임

0개의 댓글