대수 타입
대수 타입이란 여러개의 타입을 합성해서 만드는 타입을 말한다.
- 대수 타입에는
합집합 타입과 교집합 타입이 존재한다.
- 합집합은
Union 타입, 교집합은 Intersection 타입이라고 부른다.
합집합(Union) 타입

- 위와 같이 string과 number, boolean 의 유니온 타입을 정의할 수 있다. 바
| 를 이용한다.
- 이렇게 타입을 정의하면 string, number, boolean에 해당하는 값이라면 뭐든 저장할 수 있다.
- 유니온 타입에 참여하는 타입들의 개수에는 제한이 없다. 그래서 타입들을
| 를 사용해서 늘려가면 된다.
Union 타입으로 배열 타입 정의

- 이렇게 하면 다양한 타입의 요소를 보관하는 배열 타입을 쉽게 정의할 수 있다.
Union 타입과 객체 타입

- 위와 같이 여러개의 객체 타입의 유니온 타입도 얼마든지 정의할 수 있다.
- 이렇게 타입 별칭으로도 Union 타입을 정의할 수 있다.
- 위의 Union1 타입은 아래와 같이 교집합이 존재하는 두 집합으로 표현이 가능하다.

- 따라서 다음과 같은 객체들을 포함하는 타입이 된다.


- union4 객체 자체가 어디에도 없는 타입이다.
교집합(Intersection) 타입
- 다음과 같이 string과 number의 인터섹션 타입을 정의할 수 있다.
&을 이용한다.
- 그런데 number 타입과 string 타입은 서로 교집합을 공유하지 않는
서로소 집합이므로 변수 variable의 타입은 결국 never 타입으로 추론된다.

- 대다수의 기본 타입들 간에는 서로 공유하는 교집합이 없기 때문에 이런 인터섹션 타입은 보통 객체 타입들에 자주 사용된다.
Intersection 타입과 객체 타입

- 두 가지 타입의 프로퍼티를 모두 다 가지고 있는 객체만 사용 가능하다.
- 프로퍼티를 하나라도 포함하지 않는다면 타입 오류 발생한다!!
- 위 코드의 Intersection 타입을 집합으로 표현하면 다음과 같다. 유니온 타입의 그림과 차이가 명확하다.

타입 추론
- 타입스크립트는 타입이 정의되어 있지 않은 변수의 타입을 자동으로 추론한다.

- 모든 변수에 일일이 타입을 정의하지 않아도 되는 편리함을 제공한다.
- 그러나 모든 상황에서 타입을 잘 추론하는 것은 아니다.

- 이렇게 함수의 매겨변수 타입은 자동으로 추론할 수 없다.
- 그리고 타입 추론이 불가능한 변수에는 암시적으로
any 타입이 추론된다.
타입 추론이 가능한 상황들
1. 변수 선언

- 일반적인 변수 선언의 경우 초기값을 기준으로 타입이 잘 추론된다.
- 객체 타입도 잘 추론한다.
2. 구조 분해 할당

- 객체와 배열을 구조 분해 할당하는 상황에서도 타입이 잘 추론된다.
3. 함수의 반환값

- 함수 반환값의 타입은 return 문을 기준으로 잘 추론된다.
4. 기본값이 설정된 매개변수

- 기본값이 설정된 매개변수의 타입은 기본값을 기준으로 추론된다.
주의해야 할 상황들
1. 암시적으로 any 타입으로 추론

- 변수 선언할때 초기값을 생략하면 암시적인 any 타입을 추론된다. (암묵적 any 타입)
- 이때 매개변수의 타입이 암시적 any 로 추론될 때와 달리 일반 변수의 타입이 암시적 any 타입으로 추론되는 상황은 오류로 판단하지 않는다.

- 그리고 이 변수에 값으로 할당하는 그 다음 라인부터 any 타입이 해당 값의 타입으로 변화한다. (any 타입의 진화)
- 그런데 명시적으로 any 타입을 주면?? any 타입의 진화는 일어나지 않는다.
2. const 상수의 추론

- const로 선언된 상수도 타입 추론이 진행된다. 그러나 let으로 선언한 변수와는 다른 방식으로 추론된다.
(위의 경우, const는 리터럴 타입 / let은 number 타입)
- 상수는 초기화 때 설정한 값을 변경할 수 없기 때문에 가장 좁은 타입으로 추론된다.
최적 공통 타입(Best Common Type)

- 다양한 타입의 요소를 담은 배열을 변수의 초기값으로 설정하면, 최적의 공통 타입으로 추론된다.
타입 단언(Type Assertion)

- 타입 단언을 하지않고 빈 객체만 둔다면, 빈 객체는 Person 타입이 아니므로 오류가 발생한다.
- 이럴 땐 다음과 같이 빈 객체를 Person 타입이라고 타입스크립트에게 단언해주면 된다.
- 이렇듯
값 as 타입 으로 특정 값을 원하는 타입으로 단언할 수 있다. 이를 타입 단언 이라고 부른다.
- 타입 단언은 다음과 같이 초과 프로퍼티 검사를 피할때에도 사용할 수 있다.

- 위 코드에서는 breed 라는 초과 프로퍼티가 존재하지만, 이 값을 Dog 타입으로 단언하여 초과 프로퍼티 검사를 피했다.
타입 단언의 조건(규칙)
- 타입 단언에도 조건이 있다.
값 as 타입 형식의 단언식을 A as B로 표현했을 때 아래의 두가지 조건중 한가지를 반드시 만족해야 한다.
- A가 B의 슈퍼타입이다.
- A가 B의 서브타입이다.

- num1은 A(number 타입)의 값을 B(never) 타입으로 단언한다. never 타입은 모든 타입의 서브타입이므로 A가 B의 슈퍼타입이다. 따라서 단언이 가능하다.
- num2는 A(number 타입)의 값을 B(unknown) 타입으로 단언한다. unknown 타입은 모든 타입의 슈퍼타입이므로 A가 B의 서브타입이다. 따라서 단언이 가능하다.
- num3는 A(number 타입)의 값을 B(string) 타입으로 단언한다. 그러나 number 타입과 string 타입은 서로 슈퍼-서브 타입 관계를 갖지 않는다. 따라서 단언이 불가하다.
num1, num2 처럼 각 타입이 슈퍼-서브 관계에 있어서 조금이라도 겹치는 부분이 있어야 오류가 발생할 위험이 적어지기 때문이다.
다중 단언

- 타입 단언은 다중으로도 가능하다.
- 이런 다중 단언의 경우 왼쪽에서 오른쪽으로 단언이 이루어진다.
- number 타입의 값을 unknown 타입으로 단언한다.
- unknown 타입의 값을 string 타입으로 단언한다.
- 이렇듯 중간에 값을 unknown 타입으로 단언하면 unknown 타입은 모든 타입의 슈퍼타입이므로 모든 타입으로 또 다시 단언하는게 가능하다.
- 그러나 이렇게 단언하는 것은 매우 좋지 않은 방식이다. - 타입 단언은 실제로 그 값을 해당 타입의 값으로 바꾸는 것이 아니라 단순 눈속임에 불과하다. 따라서 이렇게 값을 이렇게 슈퍼-서브 관계를 갖지 않는 타입으로 단언하면 오류가 발생할 확률이 매우 높아진다.
- 그러므로 정말 어쩔 수 없이 필요한 상황에서만 이용하기를 권장한다.
const 단언

- 타입 단언때에만 사용할 수 있는 const 타입이 존재한다.
- 특정 값을 const 타입으로 단언하면 마치 변수를 const로 선언한 것 과 비슷하게 타입이 변경된다.
- 이렇게 초기화된 객체는 프로퍼티의 값을 수정할 수 없는 객체가 된다.
- const 단언을 선언하면 일일히 readonly를 붙여줄 필요없다.
Non Null 단언

- Non Null 단언은
값 as 타입 형태를 따르지 않는 단언이다. - 값 뒤에 느낌표(!) 를 붙여주면 이 값이 undefined이거나 null이 아닐것으로 단언할 수 있다.
단언은 위험한 문법이다. 실제로 그 값을 단언한 타입으로 바꾸는건 아니기 때문이다. 확실한 경우에만 사용하는 것을 추천한다.
타입 좁히기
- 조건문 등을 이용해 넓은 타입에서 좁은 타입으로 타입을 상황에 따라 좁히는 방법

- 매개변수 value의 타입이 number | string 이므로 함수 내부에서 다음과 같이 value가 number 타입이거나 string 타입일 것으로 기대하고 메서드를 사용하려고 하면 오류가 발생한다.
- 조건문을 이용해 조건문 내부에서 변수가 특정 타입임을 보장하면 해당 조건문 내부에서는 변수의 타입이 보장된 타입으로 좁혀진다.
- 따라서 첫번째 조건문 내부에서는 value의 타입이 number 타입이 되고, 두번째 조건문 내부에서는 value의 타입이 string 타입이 된다. 이를 타입 좁히기 라고 표현한다.
- 또
if (typeof === …) 처럼 조건문과 함께 사용해 타입을 좁히는 이런 표현들을 “타입 가드”라고 부른다.
instanceof 타입가드

instanceof를 이용하면 내장 클래스 타입을 보장할 수 있는 타입가드를 만들 수 있다.
- 그러나
Instanceof는 내장 클래스 또는 직접 만든 클래스에만 사용이 가능한 연산이다. 따라서 우리가 직접 만든 타입과 함께 사용할 수 없다.
in 타입 가드

- 우리가 직접 만든 타입과 함께 사용하려면 다음과 같이
in 연산자를 이용해야한다.
서로소 유니온 타입
- 서로소 유니온 타입은 교집합이 없는 타입들 즉, 서로소 관계에 있는 타입들을 모아 만든 유니온 타입을 말한다.
- 예를 들어, string과 number 타입은 교집합이 없다. 서로소 집합이다. 그래서
string | number 타입은 서로소 유니온 타입이다.

- 그러나 이렇게 코드를 작성하면 조건식만 보고 어떤 타입으로 좁혀지는지 바로 파악하기가 좀 어렵다. 결과적으로 직관적이지 못한 코드이다.
- 이럴 때에는 각 타입에
태그 프로퍼티를 추가 정의해주면 된다.

- Admin 타입에는
“ADMIN” String Literal 타입의 tag 프로퍼티를, Member 타입에는 “MEMBER” String Literal 타입의 tag 프로퍼티를, Guest 타입에는 “GUEST” String Literal 타입의 tag 프로퍼티를 각각 추가한다.

- 그러면 직관적으로 코드를 작성할 수 있다.

- 혹은 이렇게 switch 구문을 활용할 수도 있다.
- tag 프로퍼티를 추가함으로써 아래와 같은 집합의 형태를 나타낸다.
