반응형
250x250
Notice
Recent Posts
Recent Comments
Link
관리 메뉴

짧은코딩

타입 추론과 문맥 본문

TS/이펙티브 타입스크립트

타입 추론과 문맥

5_hyun 2023. 3. 13. 22:43

타입스크립트는 단순히 값만 가지고 타입 추론을 하지 않고 문맥까지 본다. 하지만 문맥까지 고려하면 추론이 이상해질 수도 있다. 

이상한 에러

-에러 코드

type Language = 'JavaScript' | 'TypeScript' | 'Python'
function setLanguage(language: Language) {
  /* ... */
}

setLanguage('JavaScript') // OK

let language = 'JavaScript'
setLanguage(language)
// ~~~~~~~~ Argument of type 'string' is not assignable
//          to parameter of type 'Language'

여기서 language의 타입 추론은 string으로 된다. 그렇기에 타입이 맞지 않는다는 에러가 난다. 이 경우에는 타입을 좁혀줘야 한다.

 

-해결 코드

type Language = 'JavaScript' | 'TypeScript' | 'Python'
function setLanguage(language: Language) {
  /* ... */
}
// 방법1
let language: Language = 'JavaScript'
setLanguage(language) // OK

// 방법2
const language2 = 'JavaScript'
setLanguage(language2) // OK

방법1처럼 language에 가능한 값을 제한하거나, 방법2처럼 const를 사용하여 타입을 좁혀주는 방법이 있다.

튜플

-에러 코드

function panTo(where: [number, number]) {
  /* ... */
}

panTo([10, 20]); // OK

const loc = [10, 20];
panTo(loc);
//    ~~~ Argument of type 'number[]' is not assignable to
//        parameter of type '[number, number]'

여기서 loc는 number[] 타입으로 추론된다.

 

-해결 코드

1. 정확한 타입 선언 제공

function panTo(where: [number, number]) {
  /* ... */
}
const loc: [number, number] = [10, 20]
panTo(loc) // OK

2. 상수 문맥 제공

function panTo(where: [number, number]) {
  /* ... */
}
const loc = [10, 20] as const // readonly [10, 20]
panTo(loc)

위 코드는 여전히 에러가 난다. const는 가리키는 참조가 변하지 않는 얕은(shallow) 상수인데, as const는 값의 내부(deeply)까지 상수라는 것을 TS에 알려준다. 따라서 위 코드의 loc의 타입은 "readonly [10, 20]"으로 추론된다. 이것은 너무 과하게 정확하게 추론되기 때문에 에러가 나게된다.

function panTo(where: readonly [number, number]) {
  /* ... */
}
const loc = [10, 20] as const
panTo(loc) // OK

과하게 추론되는 것을 막기 위해서 함수 매개변수에도 readonly를 추가하면 에러가 나지 않는다. 이렇게 하면 panTo의 where의 내용이 불변이라고 보장되기 때문에 에러가 발생하지 않는다.

객체

문맥에서 값을 분리하는 문제는 문자열 리터럴이나 튜플을 포함하는 큰 객체에서 상수를 뽑아낼 때도 발생한다.

 

-에러 코드

type Language = 'JavaScript' | 'TypeScript' | 'Python'
interface GovernedLanguage {
  language: Language
  organization: string
}

function complain(language: GovernedLanguage) {
  /* ... */
}

complain({ language: 'TypeScript', organization: 'Microsoft' }) // OK

const ts = {
  language: 'TypeScript',
  organization: 'Microsoft',
}
complain(ts)
//       ~~ Argument of type '{ language: string; organization: string; }'
//            is not assignable to parameter of type 'GovernedLanguage'
//          Types of property 'language' are incompatible
//            Type 'string' is not assignable to type 'Language'

위 코드에서 ts의 language의 타입이 string로 추론되기 때문에 에러가 발생한다. 이를 해결하기 위해서 타입 선언을 추가하거나 상수 단언을 사용해야 한다.

 

-해결 코드

const ts = {
  language: "TypeScript" as Language,
  organization: "Microsoft",
};
const ts2: GovernedLanguage = {
  language: "TypeScript",
  organization: "Microsoft",
};

complain(ts);
complain(ts2);

 

728x90
반응형
Comments