반응형

# TypeScript 

## 제네릭

  • 제네릭 : Java 등의 언어에서 재사용성이높은 컴포넌트를 만들 때 자주 활용되는 특징. 한가지 타입 보다 여러 가지 타입에서 작동하는 컴포넌트를 생성하는데 사용된다.

기본 문법

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

logText<string>('hi');

아래와 같이 인터페이스에 제네릭 선언 가능.

// 인터페이스에 제네릭 선언 방법
// interface Dropdown {
//     value: string;
//     selected: boolean;
// }

// const obj: Dropdown = { value: 'abc', selected: false };


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

const obj: Dropdown<string> = { value: 'abc', selected: false };

기존 타입 정의 방식과 제네릭의 차이점 - 함수 중복 선언의 단점

  • 아래와 같이 타입을 다르게 받기위해 중복되는 코드 사용하는것은 유지보수 측면에서 좋지 않음.
function logText(text: string) {
    console.log(text);
    //text.split('').reverse().join('');
    return text;
}

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

logText('hi');
logNumber(10);

기존 문법과 제네릭의 차이점 - 유니온 타입을 이용한 선언 방식의 문제점

  • 아래와 같은 경우 string과 number의 교집합인 공통으로 접근할 수 있는 속성, API 내에서만 자동완성 제공하는 문제점 존재.
function logText(text: string | number) {
    console.log(text);
    return text;
}

logText('hi');
logText(10);
  • 아래와 같이 변수로 받았을 경우 반환값에 대한 문제 발생.
const a = logText('hi');
a.split('');    // string과 number 타입이기 때문에 불가.

 

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

  • 제네릭 사용 시 아래와 같이 사용 가능.
function logText<T>(text: T): T {
    console.log(text);
    return text;
}

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

const login = logText<boolean>(true);

제네릭 실전 예제. (이메일, 상품 수량 선택 드롭박스)

  • 방법1) 인터페이스와 유니온 사용하여 아래와 같이 가능.
interface Email {
  value: string;
  selected: boolean;
}

interface ProductNumber {
  value: number;
  selected: boolean
}

interface TrueFalse {
  value: boolean;
  selected: boolean
}

const emails: Email[] = [
  { value: 'naver.com', selected: true },
  { value: 'gmail.com', selected: false },
  { value: 'hanmail.net', selected: false },
];

const numberOfProducts: ProductNumber[] = [
  { value: 1, selected: true },
  { value: 2, selected: false },
  { value: 3, selected: false },
];

function createDropdownItem(item: Email | ProductNumber) {
  const option = document.createElement('option');
  option.value = item.value.toString();
  option.innerText = item.value.toString();
  option.selected = item.selected;
  return option;
}

// NOTE: 이메일 드롭 다운 아이템 추가
emails.forEach(function (email) {
  const item = createDropdownItem(email);
  const selectTag = document.querySelector('#email-dropdown');
  selectTag.appendChild(item);
});

numberOfProducts.forEach(function (product) {
  const item = createDropdownItem(product);
  const selectTag = document.querySelector('#product-dropdown');
  selectTag.appendChild(item);
});

 

  • 방법2) 인터페이스에 제네릭을 사용하여 아래와 같이 가능.
interface DropdownItems<T> {
  value: T;
  selected: boolean;
}

// interface Email {
//   value: string;
//   selected: boolean;
// }

// interface ProductNumber {
//   value: number;
//   selected: boolean
// }

// interface TrueFalse {
//   value: boolean;
//   selected: boolean
// }

const emails: DropdownItems<string>[] = [
  { value: 'naver.com', selected: true },
  { value: 'gmail.com', selected: false },
  { value: 'hanmail.net', selected: false },
];

const numberOfProducts: DropdownItems<number>[] = [
  { value: 1, selected: true },
  { value: 2, selected: false },
  { value: 3, selected: false },
];

function createDropdownItem(item: DropdownItems<string> | DropdownItems<number>) {
  const option = document.createElement('option');
  option.value = item.value.toString();
  option.innerText = item.value.toString();
  option.selected = item.selected;
  return option;
}

// NOTE: 이메일 드롭 다운 아이템 추가
emails.forEach(function (email) {
  const item = createDropdownItem(email);
  const selectTag = document.querySelector('#email-dropdown');
  selectTag.appendChild(item);
});

numberOfProducts.forEach(function (product) {
  const item = createDropdownItem(product);
  const selectTag = document.querySelector('#product-dropdown');
  selectTag.appendChild(item);
});

제네릭의 타입 제한_1_.

// 제네릭의 타입 제한.
function logTextLength<T>(text: T[]): T[] {
    console.log(text.length);
    text.forEach(function (text) {
        console.log(text);
    });
    return text;
}

logTextLength<string>(['hi', 'abc']);

제네릭의 타입 제한_2_정의된 타입으로 타입 제한.

// 제네릭 타입 제한 _ 정의된 타입 이용.
interface LengthType {
    length: number;
}

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

logTextLength('a');
logTextLength(10);  // 불가.
logTextLength({ length: 10 });

제네릭의 타입제한_3_keyof로 제네릭의 타입 제한하기

// 제네릭 타입 제한 _ keyof
interface ShoppingItem {
    name: string;
    price: number;
    stock: number;
}

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

getShoppingItemOption('name');  // ctrl + space 로 자동완성 확인.
반응형

+ Recent posts