Item 37 공식 명칭에는 상표를 붙이기

About

구조적 타이핑 (Item 4 구조적 타이핑에 익숙해지기) 때문에 코드가 이상한 결과를 낼 수 있다.

interface Vector2D {
  x: number
  y: number
}
function calculateNorm(p: Vector2D) {
  return Math.sqrt(p.x * p.x + p.y * p.y)
}

calculateNorm({ x: 3, y: 4 }) // OK, 결과는 5
const vec3D = { x: 3, y: 4, z: 1 }
calculateNorm(vec3D) // OK, 결과는 5

구조적 타이핑에는 문제가 없지만, 수학적으로 따지면 2차원 벡터를 사용해야 이치가 맞다.

calculateNorm 함수가 3차원 벡터를 허용하지 않게 하기 위해 이름 명칭적 타이핑(nominal typing)을 사용하면 된다. (책에서는 공식 명칭이라고 하지만, 명칭적 타이핑이 조금 더 나은 표현인 것 같아 변경)

  • 타입이 아니라 값의 관점에서 Vector2D라고 하는 것이다.

  • 상표(brand)를 붙이면 된다.

interface Vector2D {
  _brand: '2d',
  x: number
  y: number
}
function vec2D(x: number, y: number): Vector2D {
  return { x, y, _brand: '2d' }
}
function calculateNorm(p: Vector2D) {
  return Math.sqrt(p.x * p.x + p.y * p.y)
}

calculateNorm({x: 3, y: 4}) // OK, 결과는 5
const vec3D = {x: 3, y: 4, z: 1}
calculateNorm(vec3D)
           // ~~~~~ '_brand' 속성이 ... 형식에 없습니다.
  • 단순 실수를 방지하는 데에는 충분하다.

Summary

  • 타입스크립트는 구조적 타이핑(덕 타이핑)을 사용하므로, 값을 세밀하게 구분하지 못하는 경우가 있다. 값을 구분하기 위해 명칭적 타이핑이 필요하다면 상표를 붙이는 것을 고려해야 한다.

  • 상표 기법은 타입 시스템에서 동작하지만, 런타임에 상표를 검사하는 것과 동일한 효과를 볼 수 있다.

Last updated