본문 바로가기

[코딩애플] 타입 확정하는 Narrowing / Assertion

codeConnection 2024. 6. 25.

타입스크립트의 엄격한 연산 조건

타입스크립트에서는 자바스크립트에서 가능했던 느슨한 연산을 허용하지 않는다.

 

// JS

function addNumber(x) {
    return x + 2;
}

console.log(addNumber()); // NaN

 

예를 들어 매개 변수 x를 받는다고 함수를 정의하고, 실제로 아무 것도 전달하지 않아서 undefined를 전달해 준 셈이 되는 위와 같은 함수도 에러를 undefined * 2는 말이 안 되는 식이기에 에러가 나야 할 것 같지만 자바스크립트는 Not A Number만 출력해 줄 뿐 에러를 뱉진 않는다.

 

따라서 위와 같은 코드가 쓰여졌다 하더라도 자바스크립트는 다음 코드를 이어서 읽어 내려간다.

 

하지만 타입스크립트에서는 어림도 없다.

 

// TS

function addNumber(x : number | string) {
  return x + 1;
} // 에러

 

예를 들어 위와 같은 함수가 있다고 가정하자. x라는 매개 변수에 number 타입이 올 지, string 타입이 올 지 몰라서 union type으로 둘 다 타입으로 설정해두었는데,

어차피 함수를 실행할 때 매개 변수로 2 같은 숫자를 전달해주면 2 + 1이 되니 숫자끼리의 연산이 될 것 같지만, 애초에 저 함수 자체가 에러를 뿜어 낸다.

 

이럴 때 narrowing을 해서 타입을 좁혀 주거나 assertion을 해서 타입을 단언해주면 된다. 타입을 단언한다는 것은 "내가 이 변수의 타입을 정확히 알고 있다"는 메시지를 타입스크립트에게 전달해주는 것이다.

Narrowing

// TS

function addNumber(x: number | string) {
  if (typeof x === 'number') {
    return x + 1;
  } else if (typeof x === 'string') {
    return x + 1;
  } else {
    return 0;
  }
}

 

type이 number 일 때는 어떤 연산을 해주고, string일 때는 어떤 연산을 해주고, 아무것도 아닐 때 (undefined)는 어떤 값을 반환하라는 식으로 타입을 좁혀주면 타입스크립트에서는 union 타입에서도 에러가 나지 않는다.

 

위 함수에 결과값에 대한 타입 지정이 없었지만, 매개 변수로 숫자나 문자를 받기 때문에 결과값도 숫자 아니면 문자로 되는 union 타입으로 자동 지정된다.

Assertion

일단 이 방식은 잘 안 쓴다. Narrowing 수준에서 웬만한 문제가 해결되기도 하고, 엄격한 것이 타입스크립트의 장점인데, 유연함을 부여하는 Assertion 기능은 타입스크립트의 매력을 상쇄한다.

 

Assertion은 타입스크립트에게 "내가 이 변수의 타입을 정확히 알고 있어. 이 변수의 타입은 ~~ 이거야."라고 주장하는 것이다. 이 함수의 매개 변수로는 무조건 숫자가 들어올 거라고 확정 지어서 알려주는 것이다.

function addNumber (x: number | string) {
  return (x as number) + 1;
}

console.log(addNumber(2));

 

매개 변수 as 타입 형태로 사용한다. 매개 변수에 숫자형이 올 지, 문자열이 올 지 모른다고 선언해두고 어떤 자료형이 올 지 확정하는 것이라 앞 뒤가 맞지 않는 것처럼 보이기도 한다.

 

주의할 점은 assertion은 타입을 바꿔주는 게 아니라, union type과 같이 복잡한 타입을 하나로 정확하게 확정 지어주는 역할을 하는 것이다.

 

function addNumber (x: string) {
  return (x as number) + 1;
} // 에러

 

위와 같이 타입을 string이라고 해놓고, number로 바꿔주는 형태로 사용하는 것이 아니라는 의미이다.

 

function addNumber (x: number | string) {
  return (x as number) + 1;
}

console.log(addNumber('2')); // '21'

 

그리고 위처럼 number | string 중 number 타입으로 타입을 좁혀준 것일 뿐, 매개 변수로 들어오는 것이 문자열이더라도 숫자형으로 형 변환을 해주는 것이 아니기 때문에 문자열 + 숫자의 계산이 되어서 자바스크립트 처럼 '21'이라는 이상한 연산 결과를 내보내 준다. 이걸 보기 싫어서 타입스크립트가 나온 것이기 때문에 assertion을 잘못 사용한 예시이다. 개발자가 매개 변수를 number 타입이라고 단언 했는데 실제로 매개 변수가 문자형으로 오면서 제대로 예측하지 못해서 생긴 결과이다.

 

따라서 이런 타입 단언은 최대한 사용하지 않는 것이 좋다. 타입을 좁히는 narrowing이 타입스크립트에 훨씬 어울린다.

댓글