[TypeScript] 타입 추론과 타입 단언

Main·2023년 9월 20일
0

TypeScript

목록 보기
5/8
post-thumbnail

타입 추론(type Inference) 이란?

타입 추론(type Inference)은 타입스크립트가 코드를 해석하여 타입을 정의하는 동작을 의미합니다.
변수를 초기화 하거나 함수의 파라미터에 기본값을 설정하거나 반환값을 설정했을 때 지정한 값을 적당한 타입을 제시하고 정의해주는 것을 의미합니다.


변수에서의 타입 추론

아래 코드에서 변수 a에 타입을 할당하지 않아도 해당 변수에 마우스를 올려보면 number type으로 타입이 정의되어 있는 것을 볼 수 있습니다. 타입스크립트는 할당한 초기값에 따라서 적절한 타입을 타입 추론하게 됩니다.

// 자동의 number 타입으로 타입이 정의됩니다.
let a = 10;
// 위 코드는 아래 코드와 동일합니다.
// let a:number = 10;

아래와 같이 변수를 선언하고 값을 할당하지 않을 경우에는 어떤 값이 들어올지 모르기 때문에 타입은 any 타입으로 정의됩니다.

// any 타입
let a;

함수에서의 타입 추론

아래 코드와 같이 함수에서는 파라미터와 반환 값을 타입 추론할 수 있습니다.
함수의 반환값은 파라미터의 타입과 내부 로직에 따라 자동으로 추론되게 됩니다.

// 파라미터의 a 타입과 반환값 타입이 any로 타입 추론됩니다.
function something(a) {
	return a;
}

// 파라미터의 값의 기본 값을 10으로 주었을 때 
// 값을 넘기지 않아도 되기 때문에 옵셔널 파라미터인 
// ?가 붙으며 number 타입으로 반환 값은 number 타입으로 타입 추론이 됩니다.
function something(a = 10) {
	return a;
}

// 반환 타입이 number 타입으로 타입 추론
function sum(a:number, b:number) () {
  return a + b;
}

// 반환 타입이 boolean 타입으로 타입 추론
function sum(a:number, b:number) () {
  return a === b;
}

인터페이스와 제네릭에서의 타입 추론

인터페터페이스에 제네릭을 사용할 때도 타입스크립트 내부적을 적절한 타입을 추론합니다.
인터페터페이스에서 제네릭 타입으로 넘긴 타입은 제네릭 타입으로 정의 타입으로 타입 추론됩니다. 기존 정의한 타입은 기존 타입으로 타입 추론이 이루어집니다.
아래 코드에서는 title를 string 타입으로 정의하고 value를 제네릭 타입을 정의하고 있습니다. title은 string 타입으로 value는 제네릭으로 정의한 타입으로 타입 추론이 이루어집니다.

interface Dropdown<T> {
	title: string;
    value: T;
}

let food: Dropdown<number> = {
	title: "pizza",
    value: 150000,
}

복잡한 구조에서의 타입 추론

좀 더 복잡한 구조인 인터페이스에 제네릭을 2개을 연결한 코드를 보겠습니다.
Dropdown의 인터페이스의 value 속성은 DetailedDropdown에서 넘긴 제네릭 타입인 number이 전달되어 number 타입으로 타입 추론이 일어나며, DetailedDrowdow에서는 실제로 제네릭 타입이 사용되지는 않습니다. DetailedDrowdow는 Dropdown으로 제네릭 타입을 넘겨주는 역할을 하고 있습니다.

interface Dropdown<T> {
  title: string;
  value: T;
}

// DetailedDropdown 에서의 제네릭 타입이 Dropdown으로 전달되어 해당 타입으로 타입 추론이 발생합니다.
interface DetailedDropdown<T> extends Dropdown<T> {
  topping: string;
  description: string;
}
// 제네릭 타입을 number 타입으로 넣어주어 value 값을 number 타입으로 타입 추론됩니다.
let foodDetailItem: DetailedDropdown<number> = {
  topping: Cheese,
  description: "delicious tomato pizza",
  title: "tomato pizza",
  value: 15000,
}

타입 단언(type assertion)이란?

타입 단언(type assertion)은 타입스크립트의 타입 추론에 기대하지 않고 개발자가 직접 타입을 명시하여 해당 타입으로 강제하는 것을 의미합니다.


예시 코드

아래 코드에서는 person 객체에 Profile 인터페이스를 타입 단언하여 name과 age 속성을 정의하는 코드입니다.
person은 빈 객체로 초기화 했기 때문에 name과 age 속성이 없어 person.name, person.age와 같이 속성에 접근하려고 하면 타입 에러가 발생합니다.
이것을 타입 단언을 통하여 해결할 수 있습니다. 변수 뒤에 as를 붙이면 타입단언을 할 수 있으며, person 객체 타입을 Profile 인터페이스로 타입 단언하여 name과 age 속성을 정의할 수 있도록 하였습니다.

interface Profile {
  name: string;
  age: number;
}

const person = {};

// 타입 단언을 통해 person를 Profile 인터페이스로 타입 단언합니다.
(person as Profile).name = "jon";
(person as Prfile).age = 20;

타입 단언의 문법

타입 단언은 as 키워드를 붙여 사용합니다.
타입 단언은 숫자, 문자열, 객체 등 원시 값 뿐만 아니라 변수나 함수의 호출 결과에도 사용할 수 있습니다.
아래 코드에서 getNumber의 반환 타입은 any이지만 num 변수는 타입단언에 의해 number이 됩니다.

fuction getNumber(num) {
	return num;
}

let num = getNumber("100") as number;

타입 단언의 중첩

타입 단언은 아래 코드와 같이 충첩해서 여러 번 사용이 가능합니다.
중첩된 타입 단언에서는 최종 선언된 타입이 해당 코드의 타입으로 정해집니다.

let something = (10 as any) as string

타입 단언 사용 시 주의사항

호환되지 않는 타입으로는 타입 단언할 수 없습니다.

// 호환되지 않은 타입을 타입 추론하여 타입 에러 발생 
let num = 10 as string

타입단언을 남용하지 않아야 합니다.

타입 단언은 코드를 실행하는 시점에서 아무런 역할도 하지 않기 때문에 에러에 취약한 측면이 있어 실행 에러는 미리 방지하지 못한다는 점이 있기 때문에 타입 단언을 남용해서 사용하는 것은 좋지 않습니다.

아래 코드에서 myProfile은 introduce 속성에 접근 할 수 있지만 실제로는 introduce 속성이 존재하지 않습니다. 실행 전 타입 단언을 사용하였기 때문에 타입 에러는 발생하지 않고, 실행 시점에서 타입 에러가 발생하게 됩니다.

interface Profile {
  name: string;
  id: number;
  introduce: string;
}

function getProfile(name:string, id:number) {
  return {name, id}
}

let myProfile = getProfile("jon", 100) as Profile;

// 실행 시점에서 타입 에러 발생
console.log(myProfile.introduce)

null 아님 보장 연산자(!) 타입 추론

null 아님 보장 연산자(non null assertion)는 null 타입을 체크할 때 유용하게 사용되는 연산자입니다. 또한, 타입 단언의 한 종류로 as 키워드와는 다른 용도로 사용될 수 있습니다.

null 아님 보장 연산자를 사용하면,
null 체크 로직을 일일이 추가하는 작업을 생략할 수 있습니다. 타입에 관점에서 null이 아니라고 보장하는 것이지 실제로 null값이 들어간다면 실행 에러가 발생할 수 있습니다.
즉, null 아님 보장 연산자를 사용하여 해당 값이 null이 아님을 단언할 수 있습니다.

interface Books {
  shuffle: Function
}

// null 보장 연산자를 사용하지 않는다면 null 체크 로직 추가가 필요
function shuffleBooks(books: Books | null) {
  if (books === null || books === undefined){
    return;
  }
  let result = books.shuffle();
  return result;
}

// null 체크 로직, null 아님 연산자를 사용하여
// null 값이 들어가도 타입 에러 발생 x
const book = null;
shuffleBooks(null);

정리

  • 타입 추론(type Inference)은 타입스크립트가 코드를 해석하여 타입을 정의하는 동작을 의미합니다.
    변수를 선언할 때 초기값을 할당해 놓으면 해당 초기값을 바탕으로 타입이 추론되며, 함수의 파라미터 타입, 파라미터 기본값으로 반환 타입이 추론될 수 있습니다. 인터페이스나 제네릭 역시 주어진 타입 정보로 관련 타입이 추론됩니다.

  • 타입 단언(type assertion)은 타입스크립트의 타입 추론에 기대하지 않고 개발자가 직접 타입을 명시하여 해당 타입으로 강제하는 것을 의미합니다.
    타입 단언은 as 키워드와 null아님 보장 연산자(!)를 사용해서 개발자가 직접 정의 타입을 정의합니다. 타입 단언을 사용하면 타입 에러는 해결할 수 있지만 실제 실행 시점의 에러를 해결하지 못한다는 점이 있어 주의해서 사용해야합니다.
profile
함께 개선하는 개발자

0개의 댓글