타입 추론이란?
타입 추론이 가능한 상황들
타입추론에서 주의해야할 상황들
최적 공통 타입(Best Common Type)
✏️타입추론 중간 정리
타입단언이란?
✏️타입단언 중간 정리
✏️ 총정리
🖥️ 타입 추론이란?
타입 스크립트는 점진적 타입 시스템을 채택하고 있기 때문에 타입을 별도로 지정해주지 않는다면 자동으로 타입을 추론한다.
이런 기능을 "타입추론"이라고 한다.
위 이미지는 변수 a에 number타입이라고 정의하지 않았음에도 불구하고 number타입으로 추론되는것을 확인할 수 있다.
이처럼 타입스크립트는 프로그래머에게 모든 변수에 일일이 타입을 정의하지 않아도 되는 편리함을 제공한다.
그러나 모든 상황에 타입을 잘 추론하는 것은 아니다.
위 이미지처럼 함수의 매개변수 타입은 자동으로 추론할 수 없다.
이렇게 타입 추론이 불가능한 변수(ex.매개변수)에는 임묵적으로 any타입이 추론된다.
그러나 엄격한 검사 모드(tsconfig.json파일의 strict 옵션을 true로 설정한 것)에서는 이런 암묵적 any 타입의 추론을 오류로 판단하게 된다.
이제 어떠한 상황에 타입 추론이 가능한지 살펴보자
🖥️ 타입 추론이 가능한 상황들
1. 변수선언
let a = 10; //number 타입으로 추론
let b = "hello"; // string 타입으로 추론
let c = {
id:1,
name: "김감자",
profile: {
nickname: "kimpotato",
},
urls: ["https://vitaminlog.tistory.com/"]
}; // id, name, profile, urls 프로퍼티가 있는 객체 타입으로 추론
일반적인 변수 선언의 경우 초기값을 기준으로 타입이 잘 추론된다.
변수 c처럼 복잡한 객체 타입도 문제 없이 잘 추론되고 있다.
2. 구조 분해 할당
let c = {
id:1,
name: "김감자",
profile: {
nickname: "kimpotato",
},
urls: ["https://vitaminlog.tistory.com/"]
}; // id, name, profile, urls 프로퍼티가 있는 객체 타입으로 추론
위에서 살펴본 변수 c에 대해 구조분해할당하는 경우에 타입추론이 잘 되고 있는지 확인해보자.
위 이미지와 같이 id, name, profile모두 타입 추론이 잘 되고 있는것을 확인할 수 있다.
그렇다면 배열의 경우 어떨까?
배열의 경우에도 구조 분해 할당하는 상황에서도 타입이 잘 추론되고 있는것을 확인할 수 있다.
3. 함수의 변환값
함수 반환값의 타입은 return 문을 기준으로 잘 추론되고 있는것을 확인할 수 있다.
4. 기본값이 설정된 매개변수
이번에는 매개변수를 설정해서 확인해보도록 하자.
기본값이 설정된 매개변수의 타입은 기본값을 기준으로 잘 추론되는 것을 확인할 수 있다.
🖥️ 주의해야 할 상황들
1. 암묵적으로 any 타입으로 추론
위 이미지처럼 변수를 선언할때 초기값을 생략하면 암묵적(암시적)인 any타입으로 추론된다.
참고로 이때 매개변수의 타입이 암시적 any로 추론될 때와 달리 일반 변수의 타입이 암시적 any타입으로 추론되는 상황은 오류로 판단하지 않는다.
그리고 이 변수에 위 이미지처럼 변수에 값을 할당하면 그 다음 라인부터 any타입이 해당 값의 타입으로 변화한다.
위 이미지상에서는 any 타입 > number 타입으로 변했기 때문에 toUpperCase()메서드에서 오류 메세지가 발생한다.
위 이미지처럼 d=10
다음 라인부터는 d가 number 타입이 되고, d = "hello"
다음 라인부터는 d가 string 타입이 된다.
따라서 toUpperCase()메서드에서는 에러메세지가 발생하지 않고 toFixed() 메서드에서는 오류가 발생하는것을 볼 수 잇다.
이렇게 암시적으로 추론된 any 타입은 코드의 흐름에 따라 타입이 계속 변화한다.
이를 any타입의 진화라고 표현하기도 한다.
2. const 상수의 추론
const로 선언된 상수도 타입 추론이 진행된다.
그러나 let으로 선언한 변수와는 다르게 10 Number Literal 타입으로 추론되고 있다.
위 이미지는 "hello" String Literal 타입으로 추론되고 있다.
상수는 초기화때 설정한 값을 변경할 수 없기 때문에 특별히 가장 좁은 타입으로 추론된다.
🖥️ 최적 공통 타입(Best Common Type)
위 이미지와 같이 다양한 타입의 요소를 담은 배열을 변수의 초기값으로 설정하면 최적의 공통 타입으로 추론된다.
여기서는 string도 만족해야하고 number도 만족해야하므로 union타입으로 기재되어있다.
✏️ 타입추론 정리
타입 추론이 가능한 상황은 변수선언, 구조분해할당, 함수의 반환값, 기본값이 설정된 매개변수
주의 사항
- 변수를 선언할때 초기값을 생략하면 암시적 any타입으로 추론된다.
매개변수의 타입이 암시적 any로 추론될때와 달리 일반 변수의 타입이 암시적 any타입으로 추론되는 상황에서는 오류로 판단하지 않는다.
이후 변수에 할당된 값에 따라 타입이 계속 변화하는데 이것을 any의 진화라고 표현하기도 한다. - const로 선언된 상수도 타입추론이 진행되긴 하지만 let과는 달리 Literal타입으로 추론된다.
- 최적 공통타입은 다양한 타입의 요소를 담은 배열을 변수의 초기값으로 설정하면 최적의 공통 타입으로 추론된다.
let으로 선언한 변수는 좀 더 넓은 범위로 타입을 추론해주는데 이것을 타입 넓히기 라고도 한다.
const는 리터럴 타입으로 추론되기때문에 가장 좁은 타입으로 추론된다.
🖥️ 타입 단언이란?
변수 person은 Person타입으로 정의되었지만 초기화 할때에는 빈 객체로 넣어두고 싶다고 가정하자.
그러나 타입스크립트에서는 이미지의 에러메세지처럼 이런 경우를 허용하지 않는다.
빈 객체는 Person 타입이 아니므로 오류가 발생하게 된다.
그렇다고 변수 person에 Person타입을 삭제하면 속성이 없다는 에러메세지가 뜬다.
이때 변수 person의 타입을 Person으로 하면서 오류메세지가 발생하지 않게 하는 방법은 타입 단언이 있다.
type Person = {
name: string;
age: number;
};
let person = {} as Person;
person.name = "김감자";
person.age = 300;
변수 person의 세미콜론전에 as Person을 해주면 된다.
이처럼 값 as 타입
으로 특정 값을 원하는 타입으로 단언할 수 있다. 이를 타입단언(type assertion)이라고 부른다.
type Dog = {
name: string;
color: string;
}
let dog = {
name: "김밀리",
color: "Brown",
breed: "진도", // 초과 프로퍼티 에러발생❗️
};
위 코드처럼 초과 프로퍼티에서도 타입 단언을 사용하여 초과 프로퍼티 검사를 피할 수 있다.
type Dog = {
name: string;
color: string;
}
let dog = {
name: "김밀리",
color: "Brown",
breed: "진도",
} as Dog;
위 코드처럼 초과 프로퍼티(위 예제코드의 breed)가 존재하지만 변수 dog를 Dog타입으로 단언하면 초과 프로퍼티 검사를 피할 수 있다.
타입단언의 조건
타입 단언에도 조건이 있다.값 as 타입
형식의 단언식을 A as B
로 표현했을 때 두가지 조건 중 한가지를 반드시 만족해야한다.
- A가 B의 슈퍼타입이다.
- A가 B의 서브타입이다.
이것을 그림으로 살펴보면
이렇게 표현할 수 있다.(악필 죄송합니다요)
집합의 포함관계로 보면 훨씬 이해하기 편하다
예시를 한번 살펴보도록 하자
num1, num2, num3은 모두 현재 number 타입인 상태이다.
let num1 = 10 as never; // ✅
let num2 = 10 as unknown; // ✅
let num3 = 10 as string; // ❌
위와 같이 타입 단언을 하면 as string
을 제외하고는 타입 단언이 가능하다.
이것은 타입 계층도를 보면 더 이해하기 쉬워진다.
타입계층도는 위 이미지와 같다.
그럼 이제 각각에 대해서 한번 살펴보도록 하자
num1은 현재 never타입으로 단언하고 있다.
never 타입은 모든 타입의 서브타입으로 number타입은 never의 슈퍼타입이다.
(다르게 이야기하자면 never타입은 number타입의 서브타입이다.)
never 타입은 타입 계층도에서 살펴볼 수 있듯이 모든 타입의 공집합이므로 타입 단언이 가능하다.
num2는 현재 unknown 타입으로 단언하고 있다.
unknown 타입은 모든 타입의 슈퍼타입으로 number타입은 unknown타입의 서브타입이다.
(다르게 이야기하자면 unknown타입은 number타입의 슈퍼타입이다.)
unknown 타입은 타입 계층도에서 살펴볼 수 있듯이 모든 타입의 전체집합이므로 타입 단언이 가능하다.
num3의 경우 number 타입과 string 타입은 서로 슈퍼-서브타입 관계를 갖지 않는다.
그렇기에 단언이 불가하다.
즉, 타입 계층도에서 수직관계에 위치할 경우 슈퍼-서브타입으로 단언할 수 있고, 수평관계에 위치할 경우 슈퍼-서브타입으로 단언할 수 없다.
(집합의 포함관계처럼 그림으로 그려보았을때 교집합 부분이 반드시 존재해야 슈퍼-서브타입으로 단언할 수 있다.)
다중 단언
타입 단언은 다중으로도 가능하다.
다중 단언을 이용하면 앞서 살펴본 예제인 num3같은 불가능했던 단언을 가능하도록 만들 수 있다.
let num3 = 10 as unknown as string;
이런 다중 단언의 경우 왼쪽에서 오른쪽으로 단언이 이루어진다.
따라서 순서대로 살펴보면
- number타입의 값을 unknown 타입으로 단언한다.
- unknown 타입의 값을 string 타입으로 단언한다.
이렇게 중간에 값을 unknown 타입으로 단언하면 unknown 타입은 모든 타입의 슈퍼타입이므로 모든 타입으로 또 다시 단언하는게 가능해진다.
그러나 이렇게 단언하는것은 매우 좋지 않은 방식이다.
타입 단언은 실제로 그 값을 해당 타입의 값으로 바꾸는것이 아니라 단순 눈속임에 불과하다.
따라서 값을 이렇게 슈퍼-서브 관계를 갖지 않는 타입을 억지로 단언하면 오류가 발생할 확률이 매우 높아진다.
그러므로 어쩔수없이 정말 필요한 상황에서만 이용하는것을 권장한다.
const 단언
타입 단언때에만 사용할 수 있는 const 타입이 존재한다.
특정 값을 const 타입으로 단언하면 마치 변수를 const로 선언한 것과 비슷하게 타입이 변경된다.
let num4 = 10 as const;
num4는 10 Number Literal 타입으로 단언된다.
let cat = {
name: "야옹이",
color:"yellow",
} as const;
cat은 모든 프로퍼티가 readonly를 갖도록 단언된다.
Non Null 단언
Non Null 단언은 지금까지 살펴본 값 as 타입
형태를 빠르지 않는 단언이다.
type Post = {
title: string;
author?: string;
};
let post: Post = {
title: "게시글1",
};
const len: number = post.author!.length;
값 뒤에 느낌표를 붙여주면 이 값이 undefined거나 null이 아닐것으로 단언할 수 있다.
✏️ 정리
타입 단언의 조건으로는 A가 B의 슈퍼타입이거나 A가 B가 서브타입이어야 한다.
즉, 값과 타입간의 교집합이 존재해야지만 타입 단언을 할 수 있다.
다중단언은 사용을 지양하도록 하자.
const 단언은 마치 const로 선언한것과 비슷하게 타입이 변경된다.
✏️ 총정리
타입 추론이 가능한 상황은 변수선언, 구조분해할당, 함수의 반환값, 기본값이 설정된 매개변수
주의 사항
- 변수를 선언할때 초기값을 생략하면 암시적 any타입으로 추론된다.
매개변수의 타입이 암시적 any로 추론될때와 달리 일반 변수의 타입이 암시적 any타입으로 추론되는 상황에서는 오류로 판단하지 않는다.
이후 변수에 할당된 값에 따라 타입이 계속 변화하는데 이것을 any의 진화라고 표현하기도 한다. - const로 선언된 상수도 타입추론이 진행되긴 하지만 let과는 달리 Literal타입으로 추론된다.
- 최적 공통타입은 다양한 타입의 요소를 담은 배열을 변수의 초기값으로 설정하면 최적의 공통 타입으로 추론된다.
let으로 선언한 변수는 좀 더 넓은 범위로 타입을 추론해주는데 이것을 타입 넓히기 라고도 한다.
const는 리터럴 타입으로 추론되기때문에 가장 좁은 타입으로 추론된다.
타입 단언의 조건으로는 A가 B의 슈퍼타입이거나 A가 B가 서브타입이어야 한다.
즉, 값과 타입간의 교집합이 존재해야지만 타입 단언을 할 수 있다.
다중단언은 사용을 지양하도록 하자.
const 단언은 마치 const로 선언한것과 비슷하게 타입이 변경된다.
'개발공부 > TypeScript' 카테고리의 다른 글
[타입스크립트 입문] 타입스크립트를 왜 써야하는가? (0) | 2023.09.03 |
---|---|
TypeScript 열거형(Enum)타입 (0) | 2023.05.31 |
TypeScript 타입별칭(Type Alias)과 인덱스 시그니쳐(Index Signature) (1) | 2023.05.30 |
TypeScript 객체 (0) | 2023.05.30 |
TypeScript 배열과 튜플 (2) | 2023.05.30 |