JS

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

유환빈 2023. 6. 13. 20:40

제네릭

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

제네릭을 사용하는 이유

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