성장, 그리고 노력

부족하더라도 어제보다 더 잘해지자. 노력은 절대 배신하지 않는다.

Typescript

더 나은 타입스크립트 작성하기 2 - Skills

제이콥(JACOB) 2020. 1. 1. 14:44

이전 글: 2019/12/27 - [Typescript] - 더 나은 타입스크립트 작성하기 1 - Skills

 

더 나은 타입스크립트 작성하기 1 - Skills

DRY - "Don't Repeat Yourself" 타입 스크립트 사용에 대한 글은 이전에도 작성했고, 웹 상에도 수많은 글이 존재한다. 심지어 공식 문서 또한 친절하게 잘 나와있다. 그래서 이번 글은 말 그대로 더 나은 타입..

code-masterjung.tistory.com


1편에 이어 2편이다. 역시나 타입스크립트 작성 스킬 부분을 이야기하려고 한다. 

아래와 같은 예제가 있고, 여기에 타입 지정을 하고 싶다면 어떻게 해야 할까?

const obj1 = {
  name: "jacob",
  address: "seoul",
  hobby: "coding"
};

const obj2 = {
  name: "jacob",
  address: "seoul",
  hobby: "coding",
  age: 29
};

여기서 전제는 obj1은 항상 name, address, hobby라는 프러퍼티만 갖고, obj2는 name, address, hobby, age라는 프러퍼티만 갖는다고 하자.

1 - Index Signature

첫번째 방법으로는 Index Signature를 생각할 수 있다.

type Obj = { [property: string]: string };

가장 넓게 타입을 지정한다면 이렇게 할 수 있다.  하지만 이렇게 지정하면, obj2에는 적용하지 못하고(number 타입이 존재하므로), 또한 obj1에 다른 프로퍼티가 타입만 맞는다면 무한정 추가될 수 있다. 물론 제네릭을 사용해서 위 코드를 좀 더 개선할 수 있다.

interface  Obj<T, K> {
    [property: string]: T | K;
}

const obj1: Obj<string, number> = {
  name: "jacob",
  address: "seoul",
  hobby: "coding"
};

const obj2: Obj<string, number> = {
  name: "jacob",
  address: "seoul",
  hobby: "coding",
  age: 29
};

하지만 여전히 프로퍼티를 추가할 수가 있다. 무엇인가 프로퍼티를 제한할 수 있는 것이 필요하다.

2 - Record<K, T>

두 번째 방법은 타입스크립트에서 제공하는 Record를 이용하는 것이다. Record<K, T>는 T 타입의 K 프로퍼티 집합을 만드는 것이다.

// Record<K, T> 예제
interface PageInfo {
    title: string;
}

type Page = 'home' | 'about' | 'contact';

const x: Record<Page, PageInfo> = {
    about: { title: 'about' },
    contact: { title: 'contact' },
    home: { title: 'home' },
};

Record를 사용하면 아래와 같이 정의할 수 있다.

type Obj1 = Record<"name" | "address" | "hobby" , string>;
type Obj2 = Record<"name" | "address" | "hobby" | "age", string | number>;

const obj1: Obj1 = {
  name: "jacob",
  address: "seoul",
  hobby: "coding"
};

const obj2: Obj2 = {
  name: "jacob",
  address: "seoul",
  hobby: "coding",
  age: 29
};

이제 프로퍼티의 타입을 명확하게 지정할 수 있게 되었다.

3 - mapped type

마지막 방법은 mapped type을 이용하는 것이다. 여기에 대한 개념은 이미 전 글에서 다뤘으니 생략한다.

type Obj1 = {
  [k in "name" | "address" | "hobby"]: string;
};

type Obj2 = {
  [k in "name" | "address" | "hobby" | "age"]: k extends 'age' ? number : string;
};

const obj1: Obj1 = {
  name: "jacob",
  address: "seoul",
  hobby: "coding"
};

const obj2: Obj2 = {
  name: "jacob",
  address: "seoul",
  hobby: "coding",
  age: 29
};

본인이 사용하는 프로젝트에 맞게 가능한 타입을 타이트하게 설정해 줘야지 타입 안정성이 확보될 수 있다는 점을 명심하자!

반응형