1. 생각해보기 ! ..
우리 만약 사전에 정하지 않은 타입의 파라미터를 받아와서 객체로 감싸주는 함수를 작성해보자.
만약 제네릭을 사용하지 않으면... any 타입을 사용할수도 있긴하다.
function wrap(value:any) {
return (value);
}
const result = wrap("Hello World!");
이렇게 하면 srap 함수에 어떤 값이든 인자로 넣어줄 수 있지만 문제는 result 에서 타입 추론이 어렵다는 점이 있다.
왜냐하면.. value 파라미터의 타입이 any 이기 때문에 result.value 의 타입 또한 any 로 지정되어
이 값이 문자열이라는 것을 추론할 수가 없다. ㅠㅠ
그렇다면 .. any 처럼 무엇이든 넣어줄수는 있긴하되 ! 타입추론이 가능하도록 만들고 싶다면 어떻게 할까 ?
2. 제네릭(Generic) 이란?
- 함수나 인터페이스, 타입 별칭, 클래스 등을 다양한 타입과 함께 동작하도록 만들어주는 타입스크립트의 기능
- 또한 코드의 재사용성을 높이기 위해 사용하는 기능으로, 함수나 클래스, 인터페이스, 타입에 타입 매개변수를 사용하여 다양한 타입을 처리할 수 있도록 해준다.
- 제네릭은 코드가 어떤 특정 타입에 의존하지 않고 다양한 타입을 지원하도록 만들어준다.
- < > 안에 타입 매개변수를 넣어 사용해준다.
3. 🤔 제네릭은 왜 필요할까??
일반적으로 함수를 작성할 때 특정 타입을 고정시킬 수 있다.
하지만 이렇게 하면 다양한 타입을 처리하기 어려워진다...
제네릭은 이 문제를 해결하기 위해, 함수나 클래스가 어떤 타입과도 함께 동작할 수 있도록 타입 매개변수를 사용하는 것이다.
코드를 보면서 이해해보자.
배열에서 요소를 하나씩 꺼내와야하는 상황이라고 생각해보자!
그런데 각 배열이 다른 타입을 가지고 있기 때문에 number 배열과 , string배열에 각각 별도의함수를 작성해야한다.
이것은 재사용성이 떨어지고..매우 복잡해보인다 ㅠㅠ
function getFirstNumber(arr: number[]): number {
return arr[0];
}
function getFirstString(arr: string[]): string {
return arr[0];
}
// 사용 예시
const firstNumber = getFirstNumber([1, 2, 3]); // 1
const firstString = getFirstString(["a", "b", "c"]); // "a"
그렇다면 제네릭을 사용해보자!
function getFirst<T>(arr: T[]): T {
return arr[0];
}
// 사용 예시
const firstNumber = getFirst([1, 2, 3]); // 1, T는 number로 추론됨
const firstString = getFirst(["a", "b", "c"]); // "a", T는 string으로 추론됨
const firstBoolean = getFirst([true, false, true]); // true, T는 boolean으로 추론됨
4. 사용법
(1) 함수에서 제네릭 사용하기
T 타입의 value를 받아, 같은 T 타입의 값을 반환한다.
function identity<T>(value: T): T {
return value;
}
let num = identity<number>(42); // T가 number로 대체
let str = identity<string>("hello"); // T가 string으로 대체
(2) 클래스에서 제네릭 사용하기
Box<T> 클래스는 T 타입의 content를 저장하고, 그 content를 반환하는 메서드를 가짐
class Box<T> {
content: T;
constructor(value: T) {
this.content = value;
}
getContent(): T {
return this.content;
}
}
let numberBox = new Box<number>(123);
console.log(numberBox.getContent()); // 123
let stringBox = new Box<string>("hello");
console.log(stringBox.getContent()); // "hello"
(3) 인터페이스에서 제네릭 사용학;
<K, V>: 이 인터페이스는 두 개의 타입 매개변수 K와 V를 사용하고 Pair <K,V> 는 K 타입의 key 와 V 타입의 value 가지게됨
interface Pair<K, V> {
key: K;
value: V;
}
const pair: Pair<string, number> = { key: "age", value: 30 };
console.log(pair.key); // "age"
console.log(pair.value); // 30
(4) 타입에서 제네릭 사용하기
type Result<T> = {
success: boolean;
data: T;
};
let result: Result<string> = { success: true, data: "hihilong" };
console.log(result.data); // "hihilong"
결론!
제네릭을 사용하면 함수, 클래스, 인터페이스, 타입이 어떤 특정 타입에 얽매이지 않고 다양한 타입을 처리할 수 있게 된다 !.
따라서 제네릭은 코드의 재사용성을 높이고, 타입 안전성을 유지하면서 유연한 코드를 작성할 수 있도록 도와줄수있다.
reference
책 <리액트 네이티브를 다루는 기술 - 김민준>
'TypeScript' 카테고리의 다른 글
Promise<void> vs Promise<any> 차이점 (0) | 2024.09.18 |
---|---|
[RN] 타입스크립트 개념 정리 (5) - 클래스 의 this 와 new (0) | 2024.08.24 |
[RN] 타입스크립트 개념 정리 (4) - 클래스(Class) 란? (0) | 2024.08.24 |
[RN] 타입스크립트 개념 정리 (3) - 인터페이스란? (0) | 2024.08.24 |
[RN] 타입스크립트 개념 정리 (2) - 타입의 종류 (0) | 2024.08.24 |