Type 'string | number' is not assignable to type 'number'.
만약 위와 같은 에러 메세지를 본 적이 있다면, 이는 Type Narrowing이 필요하여 발생한 에러입니다.
📌 Type Narrowing ?
: (위의 에러 메세지를 예로 들면) string | number 같은 union type에는 일반적으로 조작을 못하게 막아놨기 때문에
- 타입을 하나로 Narrowing(=좁히다) 해주거나
- 타입을 Assertion(=선언) 해주는 것이 필요하다.
Narrowing으로 판정해주는 문법들 (대표 3개)
- typeof 변수
- 속성명 in 오브젝트 자료
- 오브젝트 instanceof 부모 class
📌 typeof 연산자
: 타입을 하나로 지정해주려면 if문 등으로 해줄 수 있다.
function 함수(x: number | string) {
if (typeof x === 'string') {
return x + '1'
} else {
return x + 1
}
}
→ 여기서 주의할 점은 typeof 연산자를 쓸 때 type은 '' 로 감싸서 string 형태를 띄어야 한다.
위 함수를 해석해 보면 다음과 같다.
" x가 'string' 타입일 경우 x에 '1'을 더해주세요 "
" x가 'string' 타입이 아닐 경우(='number'타입) x에 1을 더해주세요"
📌 속성명 in 오브젝트 자료
: in 키워드로 Narrowing을 해줄 수 있다.
type Fish = { swim: string }
type Bird = { fly: string }
function check2(animal: Fish | Bird) {
if ('swim' in animal) { // swim이라는 속성이 animal이라는 오브젝트에 있는지
animal.swim
}
}
→ 여기서 주의할 점은 union type이 서로 다른 속성을 가지고 있어야 in 키워드를 사용할 수 있다.
만약, Fish와 Bird 둘 다 'swim'이라는 속성을 가지고 있으면 Narrowing이 불가능한 것!
📌 오브젝트 instanceof 부모 class
: 만약 class로부터 생산된 object라면 instanceof 연산자로 Narrowing이 가능하다.
let 날짜 = new Date()
if (날짜 instanceof Date) { // 왼쪽 오브젝트(=날짜)가 오른쪽에 있는 class(=Date)의 자식인지
console.log('today')
}
Type Narrowing 외에 Type Assertion이라는 방법도 있다
📌 Type Assertion ?
: Type을 잠깐 덮어쓰는 개념이다. *자주 사용하지 말기
- Narrowing을 할 때 사용 (여러 개의 타입을 하나로 확정 지을 때 사용)
- 실제로 타입을 바꿔주는 것이 아니기 때문에, 무슨 타입이 들어올지 100% 확실할 때 사용하는 것이 좋음
function 함수(x: number | string) {
return (x as number) + 1 // 왼쪽에 있는 변수를 number로 덮어씌워라
}
console.log(함수('123')) // 버그로 캐치 못 함(=주장만 하는거지 실제로 타입을 바꿔주지는 않음)
[번외] null & undefined 체크하는 방법
1) 변수 != null
if (변수 != null)
→ null, undefined 두 개를 동시에 거를 수 있다.
2) && 연산자 사용
function 함수(a: string | undefined) {
if (a && typeof a === 'string') {
// a가 undefined이면 if문 실행 X
// a가 string이면 if문 실행 O
}
}
→ && 기호로 비교할 때 true와 false를 넣는게 아니라 자료형을 넣으면,
&& 사이에서 처음 등장하는 falsy 값을 찾아주고, 그게 아니면 마지막 값을 남겨준다.
(*falsy 값 = false와 유사한 기능을 하는 null, undefined, NaN 이런 값들을 의미)
참고 : 코딩애플 강의
댓글