프론트엔드/Typescript
[타입스크립트] 제네릭 - 1 (개념과 예제)
zzocco94
2023. 1. 12. 17:01
애니스크립트 대신 제네릭을 사용해보자
공통으로 사용할 커스텀 훅을 만들 때, 어떤 타입의 파라미터가 들어올 지 모르면
value : any 로 하곤 했었다 (No! 지양해야 됨)
이 때 팀원 분께서 해주신 코드 리뷰!
" any 대신 사용하는 곳에 따라서 type을 넣어줄 수 있는 generic을 사용해주세요 "
이름만 들어보고 어떤 역할을 하는지 몰랐었는데
타입스크립트 강의를 들어보니 정말 유용한 개념이라 글로 남기게 되었다.
제네릭이란?
개념
- 단순하게 설명하면 '인자로 타입을 받는 함수'
// 인자로 들어온 것을 타입으로 삼는다 : "hi" => string
const log = <T extends {})(value: T) => {
console.log(value);
return value;
};
const res = log("hi");
- extends는 타입을 제한해주는 역할을 한다고 보면 된다.
// T는 string | number[]의 부분집합인 셈
const foo = <T extends (string | number)[])(args: T) => {
return args;
};
foo([1234, "asdfasdf"]);
장점
- 한번의 선언으로 다양한 타입에 재사용이 가능하다
// before : 파라미터 타입별로 함수 여러개 선언
function logText(text: string) {
console.log(text);
return text;
}
function logText(num: number) {
console.log(num);
return num;
}
// after : 하나 선언해서 재사용
// 리턴 값은 타입 추론이 되나, 엄격하게 쓰고 싶을 경우 명시해도 ok
function logText<T>(value: T): T {
console.log(value);
return value;
}
함수를 예로 들어 설명해보자면, 보통 함수를 선언할 때 파라미터 타입을 명시하는데
함수를 호출할 때 타입을 명시할 수 있다는 뜻!
예제를 통해 더 자세하게 알아보자
예제
1. 함수 파라미터 타입이 유니온일 때
- 기존 : 파라미터가 string 또는 number라면, split 메소드를 쓸 수 없다
function logText(text: string | number): string | number {
console.log(text);
return text;
}
const str = logText('abc');
str.split(''); // error! number일 수도 있기 때문에 string 일 때만 쓸 수 있는 메소드는 사용 불가
- 제네릭 : 함수를 호출할 때 타입을 명시하기 때문에, split 메소드를 사용할 수 있다.
function logText<T>(text: T): T {
console.log(text);
return text;
}
const str = logText<string>('abc');
str.split(''); // 가능
인터페이스에서 제네릭 선언하기
- 드랍다운처럼 특정 프로퍼티의 값이 자주 바뀌는 편이라면, 인터페이스에서 제네릭을 선언할 수 있다
interface Dropdown<T> {
value: T;
selected: boolean;
}
const obj1: Dropdown<number> = { value: 1, selected: false };
const obj2: Dropdown<string> = { value: 'abc', selected: false };
예제 2 - 드롭다운
- 기존 : value별로 인터페이스를 생성한다 (Email, ProductNumber)
interface Email {
value: string; // 다름
selected: boolean;
}
interface ProductNumber {
value: number; // 다름
selected: boolean;
}
const emails: Email[] = [
{ value: 'naver.com', selected: true },
{ value: 'gmail.com', selected: true },
];
const numberOfProducts: ProcuctNumber[] = [
{ value: 1, selected: true },
{ value: 2, selected: true },
];
function createDropdownItem(item: Email | ProcuctNumber) {
const option = document.createElment('option');
option.value = item.value.toString();
option.innerText = item.value.toString()
option.selected = item.selected;
return option;
}
emails.forEach((email) => {
const item = createDropdownItem(email);
const selecteTag = document.querySelector('#email-dropdown');
selectTag.appendChild(item);
});
- 제네릭 : DropdownItem 재사용
- Tip
createDropdownItem(item : DropdownItem | DropdownItem) 유니온 타입을
createDropdownItem<T>(item : DropdownItem<T>) 로 변경할 수 있다
interface DropdownItem<T> {
value: T;
selected: booelan;
}
const emails: DropdownItem<string>[] = [
{ value: 'naver.com', selected: true },
{ value: 'gmail.com', selected: true },
];
const numberOfProducts: DropdownItem<number>[] = [
{ value: 1, selected: true },
{ value: 2, selected: true },
];
function createDropdownItem<T>(item: DropdownItem<T>) {
const option = document.createElment('option');
option.value = item.value.toString();
option.innerText = item.value.toString()
option.selected = item.selected;
return option;
}
emails.forEach((email) => {
const item = createDropdownItem<string>(email);
const selecteTag = document.querySelector('#email-dropdown');
selectTag.appendChild(item);
});
출처 : 인프런 '타입스크립트 입문 - 기초부터 실전까지' 강의, 2023 원티드 프리온보딩 FE 1월 강의를 듣고 정리한 글입니다.