Skip to content

Latest commit

 

History

History
347 lines (243 loc) · 6.74 KB

File metadata and controls

347 lines (243 loc) · 6.74 KB

TypeScript 고급

제네릭(Generics)

제네릭이란?

재사용성이 높은 컴포넌트를 만들 때 자주 활용되는 특징

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


// JavaScript
function logText(text) {
  console.log(text);
  return text;
}

logText('Hello');
logText(10);
logText(true);
  • JS 문법의 경우 위와 같은 함수에서는 어떤 것이든 인자로 사용 가능

// TypeScript
function logText<T>(text: T): T {
  console.log(text);
  return text;
}

logText<string>('Hello');
  • TS의 generic을 활용하면 함수를 호출할 때 type을 정의하겠다는 약속
  • 함수를 추상화해서 더 다양한 type에서 사용 가능

image

  • 함수 호출에서 type을 정의하면 해당하는 type의 전달과 출력이 type으로 지정

기존 TS 함수의 중복 선언

function logText(text: string) {
  console.log(text);
  return text;
}

function logNumber(num: number) {
  console.log(num);
  return num;
}

logText('a')
logNumber(10)
  • 기존 TS 문법은 type에 따라 함수를 중복 정의 해야한다.
  • 유지보수 차원에서 좋지 않음

유니온 타입을 이용한 선언 방식 문제점

function logText(text: string | number) {
  console.log(text);
  return text;
}

문제점1. 지정된 여러 type이 공통으로 가지는 method에서만 preview 지원

image


문제점2. 한 가지 타입에서만 존재하는 메서드 사용 불가

image

  • 해당 함수의 결과값은 union type이므로 한 가지 type에서만 지원하는 메서드 사용 불가

제네릭의 장점과 타입 추론에서의 이점

function logText<T>(text: T): T {
  console.log(text);
  return text;
}

const str = logText<string>('a')
str.split('')

const num = logText<number>(10)
num.toLocaleString()
  • generic을 통한 type 정의를 통해 return된 값을 변수로 지정
  • 이 변수는 각 type에서 지원하는 method 사용 가능

image


인터페이스에 제네릭 선언

interface Dropdown<T> {
  value: T;
  selected: boolean;
}

const obj1: Dropdown<string> = { value: 'abc', selected: false };
const obj2: Dropdown<number> = { value: 10, selected: false };

제네릭의 타입 제한

function logTextLength<T>(text: T): T {
  console.log(text.length);
  return text;
}

logTextLength('hi');
  • 함수 내부에서 인자의 메서드 사용은 인자의 type마다 다르다.
  • generic에서 type은 호출 때 정의되므로, 함수 작성 시에는 오류 발생

image


힌트를 주자!

  • text는 length를 셀 수 있는 애라는 것을 알린다!
  • text는 배열이라고 가정
function logTextLength<T>(text: T[]): T[] {
  console.log(text.length);
  text.forEach(function (text) {
    console.log(text);
  })
  return text;
}

logTextLength<string>(['hi', 'abc']);
  • 실제 인자도 Array 형태로 전달해야 한다.

제네릭의 타입 제한2 : 정의된 타입 이용

interface LengthType {
  length: number;
}

function logTextLength<T extends LengthType>(text: T): T {
  text.length;
  return text;
}

logTextLength('abcdef');
logTextLength(['a', 'b', 'c', 'd'])
logTextLength({ length: 10 })
logTextLength(10);
  • 정의될 Type은 length 속성/메서드를 가진 LengthType의 상속을 받는 type이 된다.
  • T type은 LengthType에 추가로 정의

image


제네릭의 타입 제한3 : keyof 이용

interface ShoppingItem {
  name: string;
  price: number;
  stock: number;
}

function getShoppingItemOption<T extends keyof ShoppingItem>(itemOption: T): T {
  return itemOption;
}
getShoppingItemOption('name');

interface의 key들 중 하나를 인자로 사용


Promise를 이용한 API 함수 타입 정의

function fetchItems(): Promise<string[]> {
  let items = ['a', 'b', 'c'];
  return new Promise(function (resolve) {
    resolve(items);
  })
}
fetchItems();

enum을 이용한 타입 정의

findContactByPhone(phoneNumber: number, phoneType: string): Contact[] {
  return this.contacts.filter(
    contact => contact.phones[phoneType].num === phoneNumber
  );
}

이런 함수의 경우 인자로 phoneType을 받는다.

findContactByPhone('Homee');

그런데 이런 경우 오타를 방지할 수 없기 때문에 아래와 같이 enum을 사용


enum PhoneType {
  Home = 'home',
  Office = 'office',
  Studio = 'studio',
}
findContactByPhone(PhoneType.Home);

오타에 대한 에러를 바로 확인 가능


타입 추론(Type Inference)

타입 추론이란?

// parameter의 type으로 return 값의 type이 결정
function getB(b) {
  return b;
}
// parameter의 type으로 return 값의 type이 결정
function getB(b) {
  const c = 'hi'
  return b + c;
}
  • number + string = string으로 type 추론
  • return 값이 내부적으로 string으로 추론

인터페이스와 제네릭에서의 타입 추론

인터페이스와 제네릭

interface Dropdown<T> {
  value: T;
  title: string;
}

const shoppingItem: Dropdown<string> = {
  value: 'abc',
  title: 'hello',
}

인터페이스의 상속

interface Dropdown<T> {
  value: T;
  title: string;
}

// 관행적으로 T를 쓰지만 구분을 위해 K 사용
interface DetailedDropdown<K> extends Dropdown<K> {
  description: string
  tag: K;
}

const detailedItem: DetailedDropdown<string> = {
  value: 'abc',
  title: 'hello',
  description: '안녕하세요~~',
  tag: 'a'
}

인터페이스 A를 상속받은 인터페이스 B는 generic의 Type도 상속 가능


Best Common Type

배열 내에 type이 여러 종류가 있는 경우

const arr: (number | string | boolean)[] = [1, 2, 3, 'a', 'b', 'c', true];

유니온 타입을 이용해 배열에 들어간 개체들의 타입을 추론해 union type으로 정의

image