Item 26 : 타입 추론에 문맥이 어떻게 사용되는지 이해하기

TS가 타입을 추론하는 방식 : 값 고려 → 값이 존재하는 곳의 문맥 고려
문맥을 고려해 타입 추론 시 종종 이상한 결과 발생
→ 타입 추론에 문맥이 어떻게 사용되는지 이해함으로써 대처

  • 동일한 두 문장
// 인라인 형태
setLanguage('Javascript');

// 참조 형태
let language = 'Javascript';
setLanguage(language);
// 타입스크립트에서의 리팩터링
function setLanguage(language: string) { /* ... */}
setLanguage('Javascript'); // 정상

let language = 'Javascript';
setLanguage(language); // 정상

인라인 형태에서 TS는 함수 선언을 통해 매개변수가 Language 타입임을 알고 있음
이 값을 변수로 분리해내면, TS는 할당 시점에 타입 추론

type Language = 'JavaScript' | 'TypeScript' | 'Python';

function setLanguage(language: Language) {
    console.log(language);
}

setLanguage('JavaScript') // inline

let language = 'JavaScript';
setLanguage(language); // variable
//          ~~~~~~~~ 'string' 형식의 인수는 'Language' 형식의 매개변수에 할당될 수 없습니다.

: string으로 추론 → Language 타입으로 할당이 불가능하므로 오류 발생

  • 해결 방법
    1. 타입 선언에서 language의 가능한 값을 제한

      let language: Language = 'Javascript';
      setLanguage(language); // 정상
    2. language를 상수로 만드는 방법

      const language = 'Javascript';
      setLanguage(language); // 정상

      문맥으로부터 값을 분리함 → 근본적 문제 발생의 원인이 됨

튜플 사용 시 주의점

해당 문제의 발생 원인 : const는 얕게(shallow) 동작하기 때문

function panTo(where: [number, number]){
    console.log(where);
}
panTo([10, 20]); // inline

const loc = [10, 20]; // 문맥에서 값 분리
panTo(loc);

loc는 문맥에서 값을 분리하여 할당 시점에 number[](길이를 알 수 없는 숫자의 배열)로 추론됨

  • TS가 정확히 파악할 수 있도록 타입 선언을 제공하는 방법
// 1. any를 사용하지 않고 오류를 고칠 수 있는 방법
const loc: [number, number] = [10, 20];
panTo(loc); // 정상

// 2. '상수 문맥'을 제공하는 방법
const loc = [10, 20] as const;
panTo(loc);
//    ~~~ 'readonly [10,20] 형식은 'readonly'이며
//         변경 가능한 형식 '[number, number]'에 할당할 수 없습니다.

1번 방식 : const는 단지 값이 가리키는 참조가 변하지 않는 얕은(shallow) 상수
2번 방식 : as const는 그 값이 내부까지(deeply) 상수
라는 사실을 TS에 알려줌

any를 사용하지 않고 오류를 고칠 수 있는 최선의 해결책 : panTo 함수에 readonly 구문 추가

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

객체 사용 시 주의점

문맥에서 값을 분리하는 문제 : 큰 객체에서 상수를 뽑아낼 때도 발생

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

function complain(language: GovernedLanguage) {
    console.log(language.language);
}

complain({language : 'JavaScript', organization: 'Microsoft'});

const ts = {
    language : 'JavaScript',
    organization: 'Microsoft'
}
complain(ts);

ts객체에서의 language 타입은 string으로 추론
→ 타입 선언 추가(const ts: GoveredLanguage = …) or 상수 단언(as const)으로 해결

콜백 사용 시 주의점

콜백을 다른 함수로 전달 시, TS는 콜백의 매개변수 타입 추론을 위해 문맥 사용

function callWithRandomNumbers(fn: (n1: number, n2: number) => void) {
    fn(Math.random(), Math.random());
}

callWithRandomNumbers((a, b) => {
    console.log(a + b); // a, b type : number
})

const func = (a, b) => {
    console.log(a + b); // a, b type : any
}

callWithRandomNumbers(func);

해당 경우는 매개변수에 타입 구문을 추가해 해결 가능

const func = (a: number, b: number) => {
     console.log(a + b);
}

type callback = (a: number, b: number) => void;
const func2: callback = (a, b) => {
     console.log(a + b);
}

요약

  • 타입 추론에서 문맥이 어떻게 쓰이는지 주의해서 살펴볼 것
  • 변수를 뽑아 별도로 선언할 때 오류 발생 시 : 타입 선언 추가
  • 변수가 정말로 상수인 경우 상수 단언(as const) 사용
    • 상수 단언 사용 시 정의한 곳이 아닌 사용한 곳에서 오류 발생하므로 주의
profile
끊임없이 도전하며 사고하는 주니어 Web 개발자 유지민입니다.

0개의 댓글

Powered by GraphCDN, the GraphQL CDN