Literal Narrowing
개요
- 리터럴 타입은 집합 타입의 보다 구체적인 하위 타입을 의미
- 즉, 타입 시스템 안에서
"Hello World"
는string
이지만,string
은"Hello World"
가 아니라는 뜻
- 현재 TypeScript에는 문자열과 숫자, 그리고 boolean 까지 세 가지 리터럴 타입 존재
- 이를 사용하면 문자열, 숫자나 불리언에 정확한 값을 지정 가능
💡
리터럴이란?
컴퓨터 과학 분야에서 리터럴(literal)이란 소스 코드의 고정된 값을 대표하는 용어다. 거의 모든 프로그래밍 언어는 정수, 부동소수점 숫자, 문자열, 불린 자료형과 같은 용어를 가지고 있다. 어떤 언어는 열거 타입이나, 배열, 자료형, 객체와 같은 용어도 있다. - by wikipedia
리터럴 타입 좁히기 (Literal Narrowing)
var
또는let
으로 변수를 선언할 경우 이 변수의 값은 변경될 가능성이 있음을 컴파일러에게 알림
const
로 변수를 선언하게 되면 TypeScript에게 이 객체는 절대 변경되지 않음을 알림
// const를 사용하여 변수 helloWorld가
// 절대 변경되지 않음을 보장합니다.
// 따라서, TypeScript는 문자열이 아닌 "Hello World"로 타입을 정합니다.
const helloWorld = "Hello World";
// 반면, let은 변경될 수 있으므로 컴파일러는 문자열이라고 선언할 것입니다.
let hiWorld = "Hi World";
- 그래서 타입 좁히기란
- 무한한 수의 케이스들 (ex. 문자열) ⇒ 유한한 수의 케이스 (ex.
helloWorld
)
- 변수가 가질 수 있는 케이스를 더 적게 한정해 주는 것
- 무한한 수의 케이스들 (ex. 문자열) ⇒ 유한한 수의 케이스 (ex.
- ❓helloWorld typeOf 찍어보면 문자열 나올텐데,, 가장 구체적인 (좁은) 타입을 얻는 방식이 따로 있을까?
문자열 리터럴 타입 (String Literal Types)
- 문자열 리터럴 타입과 잘 어울리는 타입스크립트 기능
- 유니언 타입
- 타입 가드
- 타입 별칭
- 이런 기능을 함께 사용하여 문자열로 enum과 비슷한 형태 만들기 가능
- 1장에서 언급했던 내용과 같이 트리쉐이킹이 안되는 enum 보다 문자열 리터럴 타입으로 타입을 지정하면 번들링시 사이즈 최적화에 더 유리함
type Easing = "ease-in" | "ease-out" | "ease-in-out";
class UIElement {
animate(dx: number, dy: number, easing: Easing) {
if (easing === "ease-in") {
// ...
} else if (easing === "ease-out") {
} else if (easing === "ease-in-out") {
} else {
// 하지만 누군가가 타입을 무시하게 된다면
// 이곳에 도달하게 될 수 있습니다.
}
}
}
let button = new UIElement();
button.animate(0, 0, "ease-in");
button.animate(0, 0, "uneasy");
- 허용되지 않은 문자열을 사용하게 되면 오류 발생
'"uneasy"' 타입은 '"ease-in" | "ease-out" | "ease-in-out"' 타입의 매개 변수에 할당할 수 없습니다.
- 문자열 리터럴 타입은 함수 오버로딩에 사용 가능
- 타입스크립트 컴파일러가 다른 타입으로 받아들여서 가능한 것
function createElement(tagName: "img"): HTMLImageElement;
function createElement(tagName: "input"): HTMLInputElement;
// ... 추가적인 중복 정의들 ...
function createElement(tagName: string): Element {
// ... 여기에 로직 추가 ...
}
숫자형 리터럴 타입 (Numeric Literal Types)
- 문자열 리터럴과 같은 역할을 하는 숫자형 리터럴 타입도 있음
function rollDice(): 1 | 2 | 3 | 4 | 5 | 6 {
return (Math.floor(Math.random() * 6) + 1) as 1 | 2 | 3 | 4 | 5 | 6;
}
const result = rollDice();
- 주로 가능한 설정값을 설명할 때 사용
/** loc/lat 좌표에 지도를 생성합니다. */
declare function setupMap(config: MapConfig): void;
// ---생략---
interface MapConfig {
lng: number;
lat: number;
tileSize: 8 | 16 | 32;
}
setupMap({ lng: -73.935242, lat: 40.73061, tileSize: 16 });
불린형 리터럴 타입 (Boolean Literal Types)
- 불린 형태의 리터럴 타입도 있음.
- 어떤 객체가 그 속성과 서로 관련이 있는 경우에 속성값을 제한하기 위해 사용할 수 있음
- 검증 성공한 경우 isValid 는 true 로 제한한다거나, 실패한 경우 false 로 제한하는 등..
interface ValidationSuccess {
isValid: true;
reason: null;
}
interface ValidationFailure {
isValid: false;
reason: string;
}
type ValidationResult = ValidationSuccess | ValidationFailure;