본문 바로가기
JS

타입스크립트(typeScript) 제네릭, 유틸리티 타입 정리해보기

by 유환빈 2023. 6. 13.

제네릭

여러 가지 타입에서 동작하는 컴포넌트를 생성하는데 사용한다

제네릭을 사용하는 이유

ex)

여기 text라는 파라미터에 어떤 값을 넘겨 받아도 그대로 text를 반환하는 함수가있다

function getText(text) {
  return text;
}

getText('hi'); // 'hi'
getText(10); // 10

제네릭을 사용하면 함수를 호출할 때 아래와 같이 함수 안에서 사용할 타입을 넘겨줄 수 있다

함수의 인자와 반환 값에 모두 T 라는 타입을 추가했다


function getText<T>(text: T): T {
  return text;
}

// 이렇게 선언한 함수는 아래와 같이 2가지 방법으로 호출할 수 있다
1
getText<string>('hi');
getText<number>(10);
2
getText('hi');
getText(10);

제네릭 인터페이스

interface GenericLogTextFn {
  <T>(text: T): T;
}
function logText<T>(text: T): T {
  return text;
}
let myString: GenericLogTextFn = logText; // Okay

// 인터페이스에 인자 타입을 강조
interface GenericLogTextFn<T> {
  (text: T): T;
}
function logText<T>(text: T): T {
  return text;
}
let myString: GenericLogTextFn<string> = logText;

유틸리티 타입

유틸리티 타입은 이미 정의해 놓은 타입을 변환할 때 사용하기 좋은 타입 문법이다

인터페이스, 제네릭 등으로 타입을 변환할 수 있지만 유틸리티 타입을 쓰면 훨씬 더 간결한 문법으로 타입을 정의할 수 있다

Partial<T>

특정 타입의 부분 집합을 만족하는 타입을 정의할 수 있다

interface Address {
  email: string;
  address: string;
}

type MayHaveEmail = Partial<Address>;
const me: MayHaveEmail = {}; // 가능
const you: MayHaveEmail = { email: 'test@abc.com' }; // 가능
const all: MayHaveEmail = { email: 'capt@hero.com', address: 'Pangyo' }; // 가능

Pick<T, K>

T 타입으로부터 K 프로퍼티만 추출한다

interface Hero {
  name: string;
  skill: string;
}
const human: Pick<Hero, 'name'> = {
  name: '스킬이 없는 사람',
};
type HasThen<T> = Pick<Promise<T>, 'then' | 'catch'>;
let hasThen: HasThen<number> = Promise.resolve(4);
hasThen.th // 위에서 'then'만 선택하면 'then'만 제공, 'catch' 선택하면 'catch만 제공'

Omit<T, K>

T 타입으로부터 K 프로퍼티를 제거한 타입을 구성한다(Pick 타입과 반대)

interface AddressBook {
  name: string;
  phone: number;
  address: string;
  company: string;
}
const phoneBook: Omit<AddressBook, 'address'> = {
  name: '재택근무',
  phone: 12342223333,
  company: '내 방'
}
const chingtao: Omit<AddressBook, 'address'|'company'> = {
  name: '중국집',
  phone: 44455557777
}

Record<K, T>

두 개의 제네릭 타입을 받을 수 있다

K는 key 값의 타입으로, 두번째 제네릭 타입 T은 값의 타입으로 갖는 타입을 리턴한다.

type IFieldValue = {
  name: string;
  value: number;
};

type IFormName = 'event' | 'point';

const x: Record<IFormName, IFieldValue> = {
  event: {
    name: 'foo',
    value: 0,
  },
  point: {
    name: 'foo',
    value: 30,
  }
}

Readonly<T>

Type의 모든 속성을 읽기 전용(readonly)로 설정한 타입을 구성한다

interface User {
    name: string;
}

const userA: Readonly<User> = {
    name: "Jongmin",
};
userA.name = "Minjong"; //error