[TS] 타입스크립트 타입 (2) - utility type

GY·2022년 2월 5일
0

Typescript

목록 보기
2/14
post-thumbnail

타입스크립트를 더 유용하게 사용할 수 있는 방법에 대해 알아보자!

utility type

한 가지의 타입을 기본으로 해서 다른 종류의 타입으로 변환하는 것이 가능하다.


interface

인터페이스: 규격사항.

  • 어떤 특정한 규격을 정의해 구현해야 한다면 인터페이스를 쓰는 것이 더 정확하다.

  • 누군가가 구현할 사람이 있는 경우

    타입: 어떤 데이터를 담을 때 어떤 데이터를 담을 수 있을지 타입을 결정

  • 구현할 목적이 아닌 데이터를 담을 목적으로 만든다면 타입을 쓰는 것이 더 적절하다.


interface와 type alias의 차이점 - extends

type alias는 intersection을 사용해서 원하는 타입을 추가할 수 있고,
interface는 상속을 사용해서 추가할 수 있다.

  type PositionType = {
    x: number;
    y: number;
  };
  interface PositionInterface {
    x: number;
    y: number;
  }

  interface ZPositionInterface extends PositionInterface {
    z: number;
  }
  type ZPositionType = PositionType & { z: number };

interface는 중복 선언해 합칠 수 있다.

이미 선언된 타입을 한번 더 선언해 합칠 수 있다.
type alias는 중복 선언이 되지 않는다.

  type PositionType = {
    x: number;
    y: number;
  };
  interface PositionInterface {
    x: number;
    y: number;
  }

  interface PositionInterface {
    z: number;
  }
  //x,y,z를 합쳐 사용할 수 있다.

  type PositionType {
  }
  // error: Duplicate identifier 'PositionType'

type alias는 계산된 속성을 사용할 수 있다.

  type Person = {
    name: string;
    age: number;
  };
  type Name = Person['name']; // string

  type NumberType = number;
  type Direction = 'left' | 'right';
}

index

인덱스 타입은 다른 타입에 있는 키에 접근해서 그 키의 value의 타입을 그대로 선언할 수 있다.

  const obj = {
    name: 'ellie',
  };
  obj.name; // ellie
  obj['name']; // ellie

  type Animal = {
    name: string;
    age: number;
    gender: 'male' | 'female';
  };

  type Name = Animal['name']; // string
  const text: Name = 'hello';

  type Gender = Animal['gender']; //'male' | 'female'

  type Keys = keyof Animal; // 'name' | 'age' | 'gender'
  //Animal에 있는 모든 key의 타입을 유니온타입으로 keys에 할당한다.
  const key: Keys = 'gender';
  //할당된 Animal의 키 중 한 가지만 할당이 가능하다.

  type Person = {
    name: string;
    gender: Animal['gender'];
  };
  const person: Person = {
    name: 'ellie',
    gender: 'male',
  };

map

  type ReadOnly<T> = {
    readonly [P in keyof T]: T[P];
  };

  const video: ReadOnly<Video> = {
    title: 'hi',
    author: 'ellie',
  };


  //아래와 같다.
  // type VideoReadOnly = {
  //   readonly title: string;
  //   readonly author: string;
  // };

condition

type Check<T> = T extends string ? boolean : number;
//기존에 것이 상속하는 타입이 string이라면 불리언으로, 아니라면 number로 타입을 지정한다.
type Type = Check<string>; // boolean

readonly

  type ToDo = {
    title: string;
    description: string;
  };

  function display1(todo: ToDo) {
    // todo.title = 'jaja';
    /**
     * 그냥 ToDo 타입 오브젝트를 전달해주게 되면 다른 개발자가 임의로 title 등의 값을 변경할 수가 있다.
     * 불변성을 보장하기 위해 readonly를 사용한다.
     */
  }

  function display2(todo: Readonly<ToDo>) {
    // todo.title = 'jaja';
    /**
     * 이렇게만 적어도 Readonly라는 타입은 이미 내장되어있기 때문에 적용이 된다.
     * 컨트롤을 누르고 클릭해보면 어떻게 구성되어있는지 볼 수 있는데, 유틸리티 타입으로 구성된 Readonly 타입은
     * map 타입을 사용해 모든 값을 readonly로 변경시켜준다.
     */

  }

partial

partial이라는 유틸리티 타입은 기존의 타입을 유지하면서 특정 부분만 변경하고 싶을 때 사용한다.

  type ToDo = {
    title: string;
    description: string;
    label: string;
    priority: 'high' | 'low';
  };

  function updateTodo(todo: ToDo, fieldsToUpdate: Partial<ToDo>): ToDo {
    return { ...todo, ...fieldsToUpdate };
  }
  const todo: ToDo = {
    title: 'learn TypeScript',
    description: 'study hard',
    label: 'study',
    priority: 'high',
  };
  const updated = updateTodo(todo, { priority: 'low' });
  console.log(updated);

pick

  type Video = {
    id: string;
    title: string;
    url: string;
    data: string;
  };

  type VideoMetadata = Pick<Video, 'id' | 'title'>;
  //Video 타입 중 id 혹은 title만 사용하고 싶다.

  function getVideo(id: string): Video {
    return {
      id,
      title: 'video',
      url: 'https://..',
      data: 'byte-data..',
    };
  }
  function getVideoMetadata(id: string): VideoMetadata {
    return {
      id: id,
      title: 'title',
    };
  }
  //pick 이라는 utility type은 기존에 있는 타입 중 원하는 타입만 골라서 사용할 수 있다.

omit

Omit은 pick과 반대로 제외하고 싶은 타입만 명시해줄 수 있다.

  type Video = {
    id: string;
    title: string;
    url: string;
    data: string;
  };

  type VideoMetadata = Omit<Video, 'url' | 'data'>;

  function getVideo2(id: string): Video {
    return {
      id,
      title: 'video',
      url: 'https://..',
      data: 'byte-data..',
    };
  }
  function getVideoMetadata2(id: string): VideoMetadata {
    return {
      id: id,
      title: 'title',
    };
  }

record

타입을 연결하고 싶을 때 키와 내용을 지정해준다.

type PageInfo = {
  title: string;
};
type Page = 'home' | 'about' | 'contact';

const nav: Record<Page, PageInfo> = {
  home: { title: 'Home' },
  about: { title: 'About' },
  contact: { title: 'Contact' },
};
profile
Why?에서 시작해 How를 찾는 과정을 좋아합니다. 그 고민과 성장의 과정을 꾸준히 기록하고자 합니다.

0개의 댓글