Generic 함수에서 사용하기
- 제네릭은 타입 안정성을 유지하면서 재사용 가능하고 일관된 코드를 작성하도록 도와주는 기능이다.
제네릭 기본 사용법
- 함수명 옆에 <타입변수명> 을 명시하여 어떤 타입을 사용할지 명시한다.
- 해당 <타입변수명>을 매개변수 타입이나 반환 타입에서 이용할 수 있다.
- 호출할 때는 함수명 옆에 타입변수명이 아닌 사용할 타입명을 명시하면 된다.
function foo<T>(value: T): T {
return value;
}
// 호출할 때는 함수명 옆에 타입변수명이 아닌 사용할 타입명을 명시하면 된다.
foo<string>("abc");
여러개의 제네릭 타입 사용하기
function bar<Type1, Type2, Type3>(a: Type1, b: Type2, c: Type3) {
return {
a,
b,
c,
};
}
bar<number, string, boolean>(10, "10", true);
제네릭이 해결하는 문제: 타입에 특화된 함수를 일반화
- 애플리케이션에서 작성한 함수의 타입을 일반화하여 같은 로직을 여러 타입에 적용
제네릭 적용 전
- number 에도 이 로직을 적용하고 string 에도 적용하고 싶어서 두가지 타입의 중복된 함수를 선언한다.
function firstNumber(arr: number[]): number {
return arr[0];
}
function firstString(arr: string[]): string {
return arr[0];
}
// 각 타입에 대해 다른 함수를 사용한다.
let numbers1 = [1, 2, 3];
let firstNum1 = firstNumber(numbers1); // 숫자라 firstNumber 를 사용
let strings1 = ["hello", "world"];
let firstStr1 = firstString(strings1); // 문자라 firstString 을 사용
제네릭 적용 후
- 모든 타입에서 작동할 수 있는 단일 함수를 작성할 수 있다.
- 숫자나 문자열과 같은 구체적인 타입을 지정하는 대신 T로 표시 되는 타입 변수를 사용한다.
function first<T>(arr: T[]): T {
return arr[0];
}
// 각 타입에 대해 같은 함수를 사용한다.
let numbers2 = [1, 2, 3];
let firstNum2 = first(numbers2); // T is number
let strings2 = ["hello", "world"];
let firstStr2 = first(strings2); // T is string
제네릭을 사용하는 이유
- 재사용성: 함수나 클래스를 한번 작성하고 다른 유형에 계속 재활용이 가능하다.
- 타입 안정성 유지: 타입스크립트가 여전히 타입을 검사하고 잘못된 타입에 오류를 표기해준다.
- 유연성: 타입 안정성을 희생하지 않고도 코드를 더 유연하게 작성 가능하다.
class Car {
brand: string;
carName: string;
constructor(brand: string, codeName: string) {
this.brand = brand;
this.carName = codeName;
}
}
class Person {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
클래스 생성자를 제네릭으로 적용하기
- 생성자의 타입 시그니처 표현 방법이
new (매개변수): 반환 타입 이었던 것을 기억하자.
- 모든 클래스 인스턴스가 사실 타입스크립트와 자바스크립트 관점에선 객체(
{})였음을 상기해보면 편하다.
extends 이후 new (...args: any[]): {} 는 결국 모든 클래스의 생성자 시그니처를 품는다고 생각하면 된다.
function instantiator<T extends { new (...args: any[]): {} }>(
constructor: T,
...args: any[]
) {
return new constructor(...args);
}
console.log(instantiator(Car, "현대", "소나타"));
console.log(instantiator(Person, "Jake Seo", 10));