[TypeScript] 타입 추론, 타입 가드

빵호·2022년 2월 9일
0

TypeScript

목록 보기
3/3
post-thumbnail

생산성을 높이는 타입스크립트의 기능

정적 타입 언어를 사용할 때의 단점은 타입을 정의하는 데 시간과 노력이 많이 들기 때문에 생상선이 저하될 수 있다. 하지만 타입스크립트에서는 타입 추론과 타입 가드를 통해 코드를 최소화 할 수 있다.

타입 추론

명시적으로 타입 코드를 작성하지 않아도 타입스크립트가 타입을 추론할 수 있는 경우가 많다.

let 변수

let v1 = 123;
let v2 = 'abc';
v1 = 'a'; // 타입 에러
v2 = 456; // 타입에러

타입을 명시하지 않았지만 변수 v1의 타입은 숫자가 되고 변수 v2의 타입은 문자열이 된다.

let 변수는 재할당 가능하기 때문에 융통성 있게 타입이 결정되지만 const 변수는 값이 변하지 않기 때문에 더욱 엄격하게 타입이 결정된다.

const 변수

const v1 = 123;
const v2 = 'abc';
let v3: typeof v1 | typeof v2

const 변수는 리터럴 자체가 타입이 되기 때문에 변수 v1의 타입은 123, 변수 v2의 타입은 'abc'가 되고 변수 v3의 타입은 123 | 'abc' 가 된다.

배열과 객체

const arr = [10, 20, 30]; // arr1:nunber[]
const [n1, n2, n3] = arr; // n1: number, n2: number, n3: number
arr.push('a'); // 타입에러

const obj = { id: 'abcd', age: 12, language: 'korean' };
// obj: { id: string; age: number; language: string; }
const { id, age, language } = arr2;

arr은 타입 추론 덕분에 number[] 타입이 되고 비구조화 할당의 경우에도 타입 추론이 되어 모두 숫자가 된다.

obj도 타입 추론 덕분에 { id: string; age: number; language: string; } 타입이 되고 비구조화 할당 시 자동으로 타입 정보가 포함된다.

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

interface Korean extends Person {
  liveInSeoul: boolean;
}
interface Japanese extends Person {
  liveInTokyo: boolean;
}

const p1: Person = { name: 'mike', age: 23 };
const p2: Korean = { name: 'mike', age: 25, liveInSeoul: true };
const p3: Japanese = { name: 'mike', age: 23, liveInTokyo: true };
const arr1 = [p1, p2, p3];
// arr1: Person[]
const arr2 = [p2, p3];
// arr2: (Korean, Japanese)[]

Korean, Japanese는 Person에 할당 가능하기 때문에 변수 arr1의 타입은 Person[]이 되고 Korean, Japanese는 서로 할당 가능하지 않기 때문에 변수 arr2의 타입은 (Korean, Japanese)[]가 된다.

함수

function func1(a = 'abc', b = 10) {
  return `${a} ${b}`;
}
func1(3,6); // 타입 에러 첫 번째 매개변수가 숫자가 아님
cons v1: number = func('a', 1); // 타입 에러 반환값이 문자가 아님

function func2(value: number) { // 반환 타입 number | string
  if (value < 10) {
    return value;
  } else {
    return `{value} is too big`;
  }
}

기본값이 있는 매개변수는 자동으로 타입 정보가 추가되고 함수의 반환값도 타입 추론에 의해 자동으로 타입 정보가 추가된다.

return 키워드가 여러 번 등장해도 타입 추론은 잘 작동하고 함수의 반환 타입은 number | string이 된다.

타입 가드

타입 가드는 조건문을 이용해 타입의 범위를 좁히는 기능이고 잘 활용하면 불필요한 타입 단언 코드를 피해 생산성과 가독성이 높아진다.

typeof

// 타입 가드 활용 전
function print(valeu: number | string) {
  if (typeof value === 'number') {
      console.log((value as number).toFixed(2));
  } else {
     console.log((value as string).trim());
  }
}

// 타입 가드 활용 후
function print(valeu: number | string) {
  if (typeof value === 'number') {
      console.log(valuetoFixed(2));
  } else {
     console.log(value.trim());
  }
}

타입 가드가 없다면 as 키워드를 사용해 타입 단언을 해야 한다.

타입 가드 덕분에 typeof로 타입을 인식하여 문자열, 숫자에만 존재하는 메서드를 바로 호출할 수 있게 되었다.

instanceof

클래스의 경우 instanceof 키워드가 타입 가드로 사영될 수 있다.

class Person {
  name: string;
  age: number;
  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
}
class Product {
  name: string;
  price: number;
  constructor(name: string, price: number) {
    this.name = price;
    this.price = price;
  }
}
function print(valeu: Person | Product) {
  console.log(value.name);
  if (value instanceof Person) {
      console.log(value.age);
  } else {
     console.log(value.price);
  }
}

타입 가드 덕분에 if 문 안에서 Person의 age 속성에 접근할 수 있고 else 블록에서 value의 타입은 Product라고 인식한다.

instanceof는 오른쪽에 생성자 함수만 올 수 있기 때문에 인터페이스의 경우에는 사용할 수 없다.

식별 가능한 유니온 타입

인터페이스를 구별하기 위한 방법은 식별 가능한 유니온 타입을 이용하는 것이다. 식별 가능한 유니온 타입은 같은 이름의 속성을 정의하고 타입은 겹치지 않게 정의하면 된다.

interface Person {
  type: 'person';
  name: string;
  age: number;
}
interface Product {
  type: 'product';
  name: string;
  price: number;
}
function print(valeu: Person | Product) {
  if (value.type === 'person') {
      console.log(value.age);
  } else {
     console.log(value.price);
  }
}

두 인터페이스에 type이라는 같은 이름의 속성을 정의하고 속성은 고유의 문자열 리터럴 타입으로 정의한다. 그럼 값의 집합에서 서로 겹치는 부분이 없어 type 속성 값 비교를 통해 타입 가드를 동작할 수 있다.

in

function print(valeu: Person | Product) {
  if ('age' in value) {
      console.log(value.age);
  } else {
     console.log(value.price);
  }
}

in 키워드를 이용해 속성 일므의 존재를 검사하여 타입 가드를 동작한다.

식별 가능한 유니온 타입보다 속성 이름을 검사하는 게 간편하지만 타입의 종류가 많아지고 같은 이름의 속성이 중복으로 사용되면, 식별 가능한 유니온 타입을 사용하자.

profile
늘 한결같이 꾸준히

0개의 댓글