특정 타입을 다른타입으로 취급해도 괜찮은지를 판단한다.
어떠한 객체타입이 있을때 이 타입을 다른 객체타입으로 취급해도 괜찮은가?
객체타입은 프로퍼티를 기준으로 관계를 갖는다. 객체에서는 Dog타입같은 추가 프로퍼티가 있는 타입이 슈퍼타입이 되지않고, animal 같은 최소한의 프로퍼티들만으로 이루어진 타입이 슈퍼타입이 된다.
// 슈퍼타입
type Animal = {
name: string;
color: string
}
// 서브타입
type Dog = {
name: string;
color: string;
breed: string;
}
let animal = Animal = {
name: 'cat',
color: 'black'
}
let dog : Dog = {
name: 'hi',
color: 'white',
breed: 'jindo'
}
animal = dog; // 업캐스팅가능
dog = animal // 다운캐스팅이기 때문에 에러발생
초과 프로퍼티 검사란 변수를 선언할 때 객체리터럴을 직접 할당하는 경우에만 발동하는 엄격한 타입 검사이다. 초기화 시에는 실제 프로퍼티에 정의해놓지 않은 프로퍼티를 작성 할 수 없다.
// 재할당은 가능하나 (dog변수는 breed 프로퍼티가 있는데도 animal 타입에 할당할 수 있다)
animal = dog;
// 직접 초기화 시에는 안된다.
let animal2 :Animal = {
name: 'hi',
color: 'white',
breed: 'jindo' // Error: 'breed' does not exist in type 'Animal'
}
타입스크립트는 구조적 타입시스템을 사용한다. 즉, 타입 이름이 같을 필요는 없고, 필요한 속성만 정확히 들어있으면 타입이 일치하는 것으로 간주된다.
type Animal = {
name: string;
color: string;
};
type Car = {
name: string;
color: string;
};
let animal: Animal = {
name: '기린',
color: '노랑'
};
let car: Car = {
name: '모닝',
color: '파랑'
};
// Animal, Car 타입 이름이 다르지만 속성이 모두 일치하기 때문에 호환가능한 타입으로 간주된다.
animal = car;
car = animal;
하지만 객체리터럴은 개발자가 직접 만든 값이기 때문에, 타입스크립트는 이를 실수가능성이 높은 코드로 보고 더 엄격하게 검사한다.
// 타입에 정의되지 않은 breed를 넣었으니 에러가 난다
let animal2 :Animal = {
name: 'hi',
color: 'white',
breed: 'jindo' // Error: 'breed' does not exist in type 'Animal'
}
반면에, 이미 변수로 선언된 객체를 할당한 경우에는 초과프로퍼티가 있어도 필요한 속성만 있으면 에러가 발생하지 않는다. (타입에 정의된 필수 속성은 반드시 포함되어 있어야 함)
let dog : Dog = {
name: 'hi',
color: 'white',
**breed: 'jindo' // Animal타입에 정의하지않은 breed라는 초과 프로퍼티가 있는데도 가능**
}
// 가능
**animal = dog;**
let dog2 : Dog = {
name2: 'hi',
color2: 'white',
breed2: 'jindo'
}
animal = dog2; // 불가 Animal 타입에 정의한 name,color 프로퍼티가 없음
// 매개변수로 받을 dog 의 타입을 Animal로 지정해주었다.
function func(dog :Animal) {}
func({
name2: 'hi',
color2: 'white',
breed2: 'jindo' // 불가
})
func(dog2) // 변수를 통해 전달하면 가능