매개변수화된(제네릭) 타입 등 복합 타입에서는 복잡하다
복합 타입의 서브타입 규칙은 프로그래밍 언어마다 다르다
type ExistingUser = {
id: number
name: string
}
function deleteUser(user: { id?: number, name: string }) {
delete user.id
}
deleteUser(ExistingUser)
타입스크립트에서 위의 경우 객체의 프로퍼티를 삭제하더라도 타입스크립트에서는 인식하지 못한다
ExistingUser 의 타입이 deleteUser 함수 user 인수 타입의 서브 타입이기 때문에
타입스크립트는 완벽함보다는 실수를 잡는 것과 쉬운 사용 두 가지 목표를 균형 있게 달성하는 것이 목표다
파괴적 갱신은 실무에서 비교적 드물게 일어나므로 적극 제지하지 않고
슈퍼타입이 필요한 곳에 객체를 할당할 수 있도록 허용한다
type LegacyUser = {
id?: number | string
name: string
}
const legacyUser: LagacyUser ={
id: '793331',
name: 'Xin Yang'
}
function deleteUser(user: { id?: number, name: string }) {
delete user.id
}
deleteUser(lagacyUser)
// error TS2345: 'LegacyUser' 인수 타입은 '{id?: number | undefined, name: string }' 타입에 할당할 수 없음
// 'string' 타입은 'number | undefined' 타입에 할당할 수 없음
기대하는 타입의 슈퍼타입 프로퍼티를 포함하는 형태를 전달하면 타입스크립트는 에러를 발생시킨다
슈퍼타입의 id 는 string | number | undefined 인데
deleteUser 는 id 가 number | undefined 인 상황만 처리할 수 있기 때문이다
어떤 형태를 요구할 때 건넬 수 있는 타입은
요구되는 타입에 포함된 프로퍼티 각각에 대해 '<:기대하는 타입'인 프로퍼티들을 가지고 있어야 한다
기대하는 프로퍼티 타입의 슈퍼타입이 있다면 건넬 수 없다
타입스크립트의 타입은 그들의 프로퍼티 타입에 공변한다고 말한다
객체 B 에 할당할 수 있는 객체 A 가 있다면 객체 A 의 각 프로퍼티 <: B 의 대응 프로퍼티라는 조건을 만족해야 한다
타입스크립트에서 모든 복합 타입의 멤버(객체, 클래스, 배열, 함수, 반환타입)는 공변이며
함수 매개변수 타입만 반변이다
typescript strict 모드에서 함수의 매개변수는 반공변성을 띈다
strict 모드가 아니라면 함수의 매개변수는 양변성을 띈다
함수의 반환 타입은 공변성을 띈다
함수 A 가 함수 B 와 같거나 적은 수의 매개변수를 가지며 다음을 만족하면 A 는 B 의 서브타입이다