타입 추론 | 타입 단언 | 타입 가드

2022. 12. 23. 18:55프로그래밍/TypeScript

    목차

타입 추론 (Type Inference)

명시적으로 타입 선언이 되어있지 않을 경우
타입스크립트가 타입을 추론해서 제공함
let num = 12;
num = 'Hello'; // Error. 타입스크립트가 num 변수를 Number 타입으로 추론함

 

타입 스크립트가 타입을 추론하는 경우

  • 초기화된 변수
  • 기본값이 설정된 매개 변수
  • 반환 값이 있는 함수
// 초기화된 변수 num
let num = 12;

// 기본값이 지정된 매개 변수 b + 반환 값이 확실한 함수 add
function add(a: number, b: number = 2) {
  return a + b;
}

 

타입 추론 !== 엄격하지 않은 타입 선언

타입 추론을 활용해 모든 곳에 타입을 명시하지 않고도 코드 가독성을 높일 수 있음


타입 단언 (Type Assertion)

타입스크립트가 타입 추론을 통해 판단할 수 있는 타입의 범위를 넘을 경우
더 이상 추론하지 않도록 지시하는 것
변수 as 타입
function someFunc(val: string | number, isNumber: boolean) {
  if (isNumber) {
  
    // val.toFixed(2) // Error. val 이 string일 수 있음 
  
    (val as number).toFixed(2)
    
    // JSX 문법 사용 시 파싱에서 문제 발생 (.tsx 파일에서 사용 불가)
    // (<number>val).toFixed(2)
  }
}

val.toFixed(2) === 에러 발생

  • val 은 string | number 타입이기 때문에 string 일 수도 있음
  • string 타입은 toFixed() 사용이 불가능 하기 때문에 에러 발생

val as number === 타입 단언

  • val 가 number 타입이라는 것을 명시적으로 단언해 주어야 함

 

Non-null 단언 연산자

! 를 사용하는 Non-null 단언 연산자
피연산자가 Nullish (null, undefined) 값이 아님을 단언 가능

if 조건문, 타입 단언으로 해결할 수도 있지만 Non-null 연산자를 이용하면 간단함

// Error. x는 null, undefined일 수도 있음
function func(x: number | null | undefined) {
  return x.toFixed(2)
}

// if 조건문으로 x가 Truthy 값인지 판별하는 방법
function func(x: number | null | undefined) {
  if (x) {
    return x.toFixed(2)
  }
}

// 타입 단언 (변수 as 타입)
function func(x: number | null | undefined) {
  return (x as number).toFixed(2)
}

// Non-null 단언 연산자
function func(x: number | null | undefined) {
  return x!.toFixed(2)
}
// Error. null 값일 가능성이 있음
document.querySelector('.item').innerHTML;

// 타입 단언
(document.querySelector('.menu-item') as HTMLDivElement).innerHTML;
(<HTMLDivElement>document.querySelector('.item')).innerHTML;

// Non-null 단언 연산자
document.querySelector('.item')!.innerHTML;

타입 가드 (Type Guard)

NAME is TYPE 형태를 반환 타입으로 명시한 함수
타입스크립트가 추론 가능한 특정 범위에서 타입 보장 가능
// 타입 가드 
function isNumber(val: string | number): val is number {
  return typeof val === 'number';
}

function func(val: string | number) {
  if (isNumber(val)) {
    val.toFixed(2);
    isNaN(val);
    
  } else {
    val.split('');
    val.toUpperCase();
    val.length;
  }
}
// typeof 연산자를 직접 사용한 타입 가드
function someFuncTypeof(val: string | number) {
  if (typeof val === 'number') {
    val.toFixed(2)

  } else {
    val.split('')
  }
}

// in 연산자를 사용한 타입 가드
function someFuncIn(val: any) {
  if ('toFixed' in val) {
    val.toFixed(2)

  } else if ('split' in val) {
    val.split('')
  }
}

// instanceof 연산자를 사용한 타입 가드
class Cat {
  meow() {}
}
class Dog {
  woof() {}
}
function sounds(ani: Cat | Dog) {
  if (ani instanceof Cat) {
    ani.meow()
  } else {
    ani.woof()
  }
}