Item 26 타입 추론에 문맥이 어떻게 사용되는지 이해하기
About
타입스크립트는 타입을 추론할 때 단순히 값만 고려하는 것이 아니라 값이 존재하는 곳의 문맥까지도 살핀다.
그런데 문맥을 고려해 타입을 추론하면 가끔 이상한 결과가 나온다.
이때 타입 추론에 문맥이 어떻게 사용되는지 이해하고 있다면 제대로 대처할 수 있다.
Cautions with String Literals
자바스크립트는 코드의 동작과 실행 순서를 바꾸지 않으면서 표현식을 상수로 분리해 낼 수 있다.
타입스크립트에서는 다음 리팩터링이 여전히 동작한다.
이제 문자열 타입을 더 특정해 문자열 리터럴 타입의 유니온으로 바꾼다고 가정해보자. (Item 33에서 더 자세히 다룬다)
인라인(inline) 형태에서 타입스크립트는 함수 선언을 통해 매개변수가 Language
타입이어야 한다는 것을 알고 있다. 해당 타입에 문자열 리터럴 'JavaScript'
는 할당 가능하므로 정상이다.
그러나 이 값을 변수로 분리해내면, 타입스크립트는 할당 시점에 타입을 추론한다. 이 경우엔 string
으로 추론했고, Language
타입으로 할당이 불가능하므로 오류가 발생했다.
해결 방법은 두 가지이다.
타입 선언에서
language
의 가능한 값을 제한하기language
를 상수로 만들기
타입 선언에서 language의 가능한 값 제한하기
language
값에 오타가 있으면 오류를 표시해주는 장점이 있다.
language를 상수로 만들기
타입스크립트는
language
에 대해서 더 정확한 타입인 문자열 리터럴"JavaScript"
로 추론할 수 있다.language
를 재할당해야 한다면 타입 선언이 필요하다. (Item 21 타입 넓히기)
그런데 이 과정에서 사용되는 문맥으로부터 값을 분리했다. 문맥과 값을 분리하면 추후에 근본적인 문제를 발생시킬 수 있다. 이러한 문맥의 소실로 인해 오류가 발생하는 몇 가지 경우와, 이를 어떻게 해결하는지 하나하나 살펴보자.
Cautions with Tuples
첫 번째 경우는 [10, 20]
이 튜플 타입 [number, number]
에 할당 가능하다.
두 번째 경우는 타입스크립트가 loc
의 타입을 number[]
로 추론한다. (즉, 길이를 알 수 없는 숫자의 배열)
그러면 any
를 사용하지 않고 오류를 고쳐보자.
1. Type Declaration
타입스크립트가 의도를 제대로 파악하도록 타입 선언을 제공해 해결할 수 있다.
2. Provide const
Context
const
Contextany를 사용하지 않고 오류를 고칠 수 있는 또 다른 방법은 '상수 문맥'을 제공하는 것이다. 단, as const
만으로는 readonly
가 붙어버리니 함수를 고쳐줘야 한다.
as const는 문맥 손실과 관련된 문제를 깔끔하게 해결할 수 있지만, 단점이 있다.
만약 타입 정의에 실수가 있다면(e.g., 튜플에 세 번째 요소 추가) 오류는 타입 정의가 아니라 호출되는 곳에서 발생한다.
특히 여러 겹 중첩된 객체에서 오류가 발생한다면 근본적인 원인을 파악하기 어렵다.
Cautions with Objects
문맥에서 값을 분리하는 문제는 문자열 리터럴이나 튜플을 포함하는 큰 객체에서 상수를 뽑아낼 때도 발생한다.
이 문제는 타입 선언을 추가하거나 (const ts: GovernedLanguage = ...
) 상수 단언(as const
)을 사용해 해결한다. (Item 9 타입 단언보다는 타입 선언을 사용하기)
Cautions with Callbacks
콜백을 다른 함수로 전달할 때, 타입스크립트는 콜백의 매개변수 타입을 추론하기 위해 문맥을 사용한다.
callWithRandomNumbers
의 타입 선언으로 인해 a
와 b의 타입이 number
로 추론된다.
콜백을 상수로 뽑아내면 문맥이 소실되고 noImplicitAny
오류가 발생한다.
이런 경우에는 매개변수에 타입 구문을 추가해 해결할 수 있다.
또는 가능할 경우 전체 함수 표현식에 타입 선언을 적용하면 된다. (Item 12 함수 표현식에 타입 적용하기)
Summary
타입 추론에서 문맥이 어떻게 쓰이는지 주의해서 살펴봐야 한다.
변수를 뽑아서 별도로 선언했을 때 오류가 발생한다면 타입 선언을 추가해야 한다.
변수가 정말로 상수라면 상수 단언(
as const
)를 사용해야 한다. 그러나 상수 단언을 사용하면 정의한 곳이 아니라 사용한 곳에서 오류가 발생하므로 디버깅에 있어 주의해야 한다.
Last updated