자바스크립트는 덕 타이핑 기반이다. 덕 타이핑이란, 객체가 어떤 타입에 부합하는 변수와 매서드를 가질경우 객체를 해당 타입에 속하는 것으로 간주하는 방식이다. 타입스크립트는 이를 모델링 하기 위해서 구조적 타이핑을 사용한다.
아래 코드를 보면 Vector
와 Square
간의 관계를 전혀 선언하지 않았지만 타입을 넘겨줄 수 있다.
interface Vector {
x: number;
y: number;
}
function normalize(input: Vector) {
return Math.sqrt(input.x * input.x + input.y * input.y)
}
interface Square {
name: string
x: number;
y: number
}
const square: Square = {name: 'sq', x:1, y:1}
normalize(square)
normalize3D
함수는 정규화된 값을 구하기 위해 normalize
함수를 내부적으로 호출했지만,
normalize
함수의 인자로 Vector3D
타입을 넘겨도 타입체커가 문제로 인식하지 않기 때문에, 3차원에 대해서 정규화를 하지 않은 값을 리턴하는 버그가 발생한다.
interface Vector {
x: number;
y: number;
}
function normalize(input: Vector) {
return Math.sqrt(input.x * input.x + input.y * input.y)
}
interface Vector3D {
x: number;
y: number;
z: number
}
function normalize3D(input:Vector3D) {
return normalize(input)
}
매개변수의 속성들이 매개변수의 타입에 선언된 속성만 가질거라 생각하기 쉽다. 이러한 타입은 봉인된(sealed) 또는 정확한(precise) 타입이라고 불리며 타입스크립트에서는 표현할 수 없다. 좋든 싫든 타입스크립트에서는 타입은 열려(open)있다.
아래 코드를 보면 key
는 x
또는 y
중 하나이고 값은 number
로 생각하기 쉽지만, 타입 오류가 발생한다
function sum(input: {x:number, y: number}) {
let result = 0;
for(let key in input) {
result += input[key] // No index signature with a parameter of type 'string' was found on type '{ x: number; y: number; }'
}
return result
}
왜냐하면 input
으로 오는 값은 Vector
가 가진 속성을 포함한 다른 객체가 올 수 있기 때문에 타입스크립트가 오류를 발생시킨다.
sum({x: 1, y: 1, z: '높이'})
해결: 루프보다는 모든 속성을 각각 더하는 구현이 더 낫다.
function sum(input: {x:number, y: number}) {
return input.x + input.y
}
- 자바스크립트는 덕타이핑 기반이고 타입스크립트는 이를 모델링하기 위해 구조적 타이핑을 사용한다.
- 어떤 인터페이스에 할당 가능한 값이라면, 값은 명시적으로 선언된 타입에 봉인되어 있지 않고 추가로 다른 속성이 있을 수 있다.
- 구조적 타이핑은 추상화를 가능하게 하며 유닛 테스트에 유용하다.