개념
타입스크립트가 타입을 추론할 때 사용하는 방법으로, 너무 광범위 하지 않으면서도 일단 추론된 타입이 최대한 바뀌지 않는 방향으로 추론된다. 타입 넓히기를 배우면 타입을 따로 선언하지 않은 경우 타입스크립가 어떤 식으로 타입을 추론하는 지 예측할 수 있고 적절하게 제어할 수 있다.
모든 코드는 깃헙에서 직접 실행해볼 수 있다 🐱 (https://github.com/erie0210/effective-typescript/tree/main)
적용
예시1: 아래와 같은 예시를 실행해보면 x 타입을 제대로 추론하지 못해서 에러가 발생한다.
interface Vector3 {
x: number;
y: number;
z: number;
}
function getComponent(vector: Vector3, axis: 'x' | 'y' | 'z'){
return vector[axis];
}
let x = 'x';
let vec = { x:10, y:20, z:30 };
getComponent(vec, x); // <----------- 에러 발생:
// ~~ Argument of type 'string' is not assignable to parameter of type '"x" | "y" | "z"'
언뜻 보면 axis 타입이 'x' | 'y' | 'z' 이기 때문에 'x' 를 할당받은 x를 넣어주면 될 것 같지만 실제 ts에서는 아래와 같은 에러가 발생한다. 설명을 읽어보면 string 타입인 x를 'x' | 'y' | 'z' 에 할당할 수 없다는 메시지이다.
Argument of type 'string' is not assignable to parameter of type '"x" | "y" | "z"'
'x'가 왜 stirng로 추론되었는 지 이해하려면 '타입 넓히기'를 이해해야한다.
런타임에서는 모든 타입이 유일하다. let c = '1' 이라는 코드가 불러와져서 사용되는 시점에는 무조건 고정된 하나의 값을 가진다는 의미이다. TS가 작동하는 빌드 타임 시점에서는 타입을 추론해야한다. 예를 들어서 아래와 같이 작성된 코드가 있다면 나올 수 있는 여러 타입이 있는데, 이 중에서 가장 런타임 시점에 바뀌지 않을 타입으로 선언하려고 한다. (이를 명확성과 유연성 사이 균형이라고 한다.)
const mixed = ['x', 1];
// 예상 가능한 추론 타입
// ('x'|1)[] ---> 'x'나 1을 가지는 배열
// [string, number] ---> 튜플
// (string|number)[] -------------------> 실제 TS 가 추론하는 타입
// [any, any]
// any[]
코드 작성 또는 빌드 타임 시점에 보다 정확하게 타입을 제어하기 위해서 아래와 같은 방법을 사용할 수 있다.
방법1: let 이 아닌 const를 사용하는 것이다. const 를 사용하면 재할당 할 수 없으므로 TS는 더 좁은 타입으로 추론한다.
아래의 예시는 이 글의 가장 첫번째 예시에 이어진다. 하지만 이번엔 const를 이용해 선언했기 때문에 변수 y는 항상 'y' 타입을 가지고 (string이 아닌) 이 때문에 'x' | 'y' | 'z' 유니언 타입의 부분 집합이 될 수 있다.
// 타입 넓히기 제어 방법
// 방법 1 : const 사용
const y = 'y'
let vec2 = { x:10, y:20, z:30}
getComponent(vec, y)
다만 const를 사용할 때에도 예외가 있다. 객체 {} , 튜플 [], 배열 []이다.
아래와 같이 const로 선언되었다고 할지라도 x에 어떤 값이든 할당된다. Call By Reference 때문인데, 배열을 예로 들면 배열 그 자체는 const로 선언되지만 배열 안의 개별 값들은 주소값을 가지고 있기 때문에 실제 주소값에 들어가는 값들은 바뀔 수 있는 것이다.
// 예외: 객체, 배열, 튜플
const v = {
x: 1
}
v.x = 3
v.x = '3'
v.y = 4
이런 예외를 해결하는 방법으로는 아래와 같이 두 가지가 있다.
(1) 명시적으로 타입을 선언하기 (2) const 단언하기
// 예외에 대한 제어 방법 1: 타입선언
const v2: { x:1|3|5 } = {
x:1
}
// 예외에 대한 제어 방법 2: const 이용
const v3 = {
x:1 as const,
y: 3
}
위의 예외적인 케이스를 주의하면서 const를 사용하면 보다 정확하게 TS 타입 추론을 사용할 수 있다.
'백엔드 개발' 카테고리의 다른 글
#031. 쿼리개선: N*M -> N+M 개선하기 (0) | 2023.04.09 |
---|---|
#030. CORS 에러 원인과 해결 (feat. 서버에서 CORS 테스트 하기) (0) | 2023.04.08 |
#029. 리팩터링: any 보다 unknown 타입 사용하기 (feat. 이중 단언문) (0) | 2023.04.05 |
#028. TS 타입 좁히기(2) Brand 사용해 nominal typing 하기 (0) | 2023.03.22 |
#027. TS 타입 좁히기(1) Tagged Union (0) | 2023.03.08 |