부모 타입(상위 타입)의 변수에 자식 타입(하위 타입)의 값을 할당하는 것을 업 캐스팅
반대의 경우를 다운 캐스팅이라고 합니다.
unknown
타입은 타입 계층도에서 최상단에 위치한 타입입니다.
따라서 모든 타입은 unknown
타입으로 업 캐스팅이 가능합니다.
let a: unknown = 1; // number -> unknown
let b: unknown = "hello"; // string -> unknown
let c: unknown = true; // boolean -> unknown
let d: unknown = null; // null -> unknown
let e: unknown = undefined; // undefined -> unknown
let f: unknown = []; // Array -> unknown
let g: unknown = {}; // Object -> unknown
let h: unknown = () => {}; // Function -> unknown
하지만 반대로 unknown
타입은 다른 타입으로 다운 캐스팅이 불가능합니다.(any
타입 제외)
never
타입은 타입 계층도의 최하위에 위치한 타입입니다.
let neverVar: never;
let a: number = neverVar; // never -> number
let b: string = neverVar; // never -> string
let c: boolean = neverVar; // never -> boolean
let d: null = neverVar; // never -> null
let e: undefined = neverVar; // never -> undefined
let f: [] = neverVar; // never -> Array
let g: {} = neverVar; // never -> Object
따라서 never
타입은 모든 타입으로 업 캐스팅이 가능합니다.
반대로 어떤 타입도 never
타입으로 다운 캐스팅이 불가능합니다.
void
타입은 아무것도 반환하비 않는 함수의 반환값 타입으로 주로 사용되며 unknown
타입의 상위 타입입니다.
function noReturnFunc(): void {
console.log("hi");
}
따라서 void
타입을 반환값 타입으로 지정한 함수에서 undefined
값을 반환하여도 가능합니다.
업 캐스팅이 가능하기 때문입니다.
void
타입의 하위 타입은 undefined
와 never
타입만 존재하기 때문에 void
타입 변수에는 undefined
, never
타입의 값 외의 다른 타입의 값은 할당할 수 없습니다.
let voidVar: void;
voidVar = undefined; // undefined -> void (ok)
let neverVar: never;
voidVar = neverVar; // never -> void (ok)
any
타입은 치트키 타입입니다.
모든 타입으로 업 캐스팅이 가능하고 모든 타입으로 다운 캐스팅도 가능합니다.
type Animal = {
name: string;
color: string;
};
type Dog = {
name: string;
color: string;
breed: string;
};
let animal: Animal = {
name: "기린",
color: "yellow",
};
let dog: Dog = {
name: "돌돌이",
color: "brown",
breed: "진도",
};
animal = dog; // ✅ OK
dog = animal; // ❌ NO
타입스크립트는 프로퍼티를 기준으로 타입을 정의하는 구조적 타입 시스템을 따릅니다.
따라서 프로퍼티 갯수가 더 많은 Dog
타입이 상위 타입이라고 생각할 수 있지만 그 반대입니다.
쉽게 생각하면 Animal
타입은 name
, color
프로퍼티를 가지고 있는 모든 객체의 집합입니다.
Dog
타입은 name
, color
, breed
프로퍼티를 가지고 있는 모든 객체의 집합입니다.
따라서 Dog
타입에 속하는 객체라면 당연히 Animal
타입에도 속하게 됩니다. 하지만 그 반대는 성립하지 않습니다.
따라서 Animal
타입은 Dog
타입의 상위 타입이라고 말할 수 있습니다.
그러므로 Dog
타입은 Animal
타입으로 업 캐스팅이 가능하지만, Animal
타입은 Dog
타입으로 다운 캐스팅이 불가능합니다.
type Book = {
name: string;
price: number;
};
type ProgrammingBook = {
name: string;
price: number;
skill: string;
};
(...)
let book2: Book = { // 오류 발생
name: "한 입 크기로 잘라먹는 리액트",
price: 33000,
skill: "reactjs",
};
Book
타입과 ProgrammingBook
타입을 타입 별칭으로 정의했습니다.
그리고 Book
타입 변수를 선언하고 객체를 할당하였습니다. name
, price
, skill
프로퍼티를 갖는 객체는 Book
타입의 하위타입이기 때문에 업 캐스팅이 가능해야 합니다.
하지만 위와 같은 경우에 오류가 발생합니다.
이유는 초과 프로퍼티 검사 때문입니다.
초과 프로퍼티 검사는 변수를 객체 리터럴로 초기화 할 때 발동합니다.
Book
타입은 name
, price
를 프로퍼티로 갖는 객체 타입인데, skill
프로퍼티를 갖는 객체 리터럴을 Book
타입 변수에 할당하려고 했기 때문에 초과 프로퍼티 검사가 발동합니다.
초과 프로퍼티 검사는 객체 리터럴을 할당하는 경우에만 발동되기 때문에 값을 미리 다른 변수에 보관하고 이 변수를 할당하면 가능합니다.
초과 프로퍼티 검사는 함수의 매개변수에도 동일하게 작동합니다.
function func(book: Book) {}
func({ // 오류 발생
name: "한 입 크기로 잘라먹는 리액트",
price: 33000,
skill: "reactjs",
});
해결 방법도 동일하게 다른 변수에 할당한 후 변수를 인수로 넘겨주면 됩니다.