
⇒ 어떤 객체 타입을 다른 객체타입으로 취급해도 괜찮은지에 대한 문제
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; // 업캐스팅
dog = animal; // 에러발생, 다운캐스팅
Animal 타입이 Dog 타입을 포함하는 슈퍼타입이라는 의미
Dog는 Animal 타입의 서브 타입을 의미한다.
객체들은 property를 기준으로 관계를 가진다.
Dog 타입이 Animal 타입의 프로퍼티를 다 가지면서, breed를 더 가지고 있는데, 이렇게 보면 Dog 타입이 슈퍼타입으로 여길 수 있다.
하지만, 타입스크립트는 프로퍼티를 기준으로 타입을 정의하는 구조적 타입 시스템을 따른다.
Dog 타입은 name, color을 가지고 있으므로 Animal 타입의 규칙에도 해당한다.
반대로, Animal 객체는 Dog 타입 객체에 포함되지 않는다(breed가 없음).
⇒ 추가 프로퍼티가 없는 조건이 적은 타입이 슈퍼타입이 된다.
book = programmingBook;
위에서는 업캐스팅이 일어나서 대입이 가능하지만, 아래 코드를 보면 skill이라는 프로퍼티를 넣으면 정의되지 않았다고 하면서 오류가 발생한다. 하나는 되고 하나는 안되는 상황이 발생한다.
// 초과 프로퍼티 검사
type Book = {
name: string;
price: number;
};
let book2: Book = {
name: "한 입 크기로 잘라먹는 리액트",
price: 33000,
skill: "reactjs", // 오류 발생
};
이는 실제 타입에는 정의해 놓지 않은 프로퍼티가 있다면 안되도록 막는 검사가 초과 프로퍼티다.
⇒ 여러개의 타입을 합성해서 새롭게 만들어낸 타입
⇒ 합집합 타입과 교집합 타입이 존재한다.
let a: string | number | boolean;
a = 1;
a = "hello";
a = true;// a에는 number, string, boolean타입 모두 들어갈 수 있다.
Union 타입을 만들 때, “|” 를 이용해서 만들 수 있는 것은 무한대다.
type Dog = {
name: string;
color: string;
};
type Person = {
name: string;
language: string;
};
type Union1 = Dog | Person;
let union1: Union1 = { // Dog
name: "",
color: "",
};
let union2: Union1 = { // Person
name: "",
language: "",
};
let union3: Union1 = { // 모든 프로퍼티를 넣었을 때
name: "",
color: "",
language: "",
};
let union4: Union1 = { // 오류 발생
name: "",
};
union1은 Dog 타입의 프로퍼티를, union2는 Person 타입의 프로퍼티를, union3는 두 타입을 모두 충족할 수 있도록 모든 프로퍼티가 포함되어 있다.
하지만, union4에서는 오류가 발생한다.
이는 집합으로 이해하면 쉬운데, 위 그림을 보면 union4는 어느 집합에도 속하지 않기 때문에, 오류가 발생하는 것이다.
&를 사용한다.
let variable: number & string;
ex) number 타입과 string 타입의 교집합을 갖는 타입
⇒ number 타입과 string 타입은 공집합이므로, never 타입이 된다.
⇒ 즉, 기본 타입들 중에는 서로 공유되거나 겹치는 값들이 없기 떄문에, 교집합 타입은 객체 타입에서 많이 사용된다.
type Dog = {
name: string;
color: string;
};
type Person = {
name: string;
language: string;
};
type Intersection = Dog & Person;
let intersection: Intersection = {
name: "",
color: "",
language: "",
};
교집합은 Dog와 Person에 모두 포함이 되야 하므로, 모든 프로퍼티를 갖고 있는 객체만을 교집합 타입으로 포함될 수 있다.
따라서, 하나라도 프로퍼티를 빼먹으면 포함되지 않는다.
타입을 정의하지 않아도 값을 넣어서 초기값을 넣어주면 타입스크립트가 알아서 타입을 추론해주는 것을 의미.
let a = 10;
let b = "hello";
let c = {
id: 1,
name: "제노",
profile: {
nickname: "zeno",
},
};
let { id, name, profile } = c;
let [one, two, three] = [1, "hello", true];
⇒ 이는 타입을 추론하는 기준을 변수의 초기값을 토대로 추론하는 것이다.
function func() {
return "hello";
}
⇒ 이는 반환값을 기준으로 추론하는 것이다.
function func2(message = "hello") {
return "hello";
}
let d; // 초기값 생략 -> any타입으로 추론 => 타입이 변신하듯이 바뀌는 상황을 any타입의 진화라고 부른다.
// 변수를 선언하고 초기값을 넣어주지 않으면 암묵적인 any타입으로 추론됌
// 암묵적 any타입이란?
// 일단 아무런 정보가 없으니 암묵적 any타입으로 추론할게~ 라는 의미
d = 10; // 10이 들어감으로써 number 타입으로 추론
// 10을 넣는 순간 any -> number로 진화
d.toFixed();
d.toUpperCase(); // (x)
d = "hello"; // string을 넣어도 문제가 안됌. 또한 string으로 추론됌
// number -> string으로 진화
d.toUpperCase();
d.toFixed(); // (x)
let e: any; // 명시적으로 any타입을 정의하면 다 any타입이므로 진화가 없다.
// 암묵적으로 any를 갖게 되면 타입이 계속해서 진화한다.
const num = 10;
// 어차피 상수이기 때문에, 10 이외에는 다른 값을 담지 않음. 따라서, number literal 타입 10으로 추론됌
const str = "hello";
let arr = [1, "string"];
// number 와 string의 유니온타입으로 추론됌
// number와 string 타입을 만족해야 하기 때문에 union 타입으로 추론되는 것임