제네릭(Generic) 이란?
제네릭은 어떠한 클래스 혹은 함수에서 사용할 타입을 그 함수나 클래스를 사용할 때 결정하는 프로그래밍 기법이다.
generic의 단어 뜻은 일반적인, 총칭의, 포괄적인 이다.
즉, 타입을 일반화하는 것을 의미한다.
특정 타입에 의존하지 않고 다양한 타입에 대해 동작할 수 있는 함수나 클래스 등을 작성할 수 있게 해주기 때문이다. → 함수와 클래스의 범용적인 사용이 가능해진다.
콘크리트 타입 대신 사용 가능
제네릭없이 함수를 정의한다면 파라미터와 리턴 값에 특정 타입을 주어야 한다.
function identity(arg: number): number {
return arg;
}
타입이 확실하지 않은 경우에는 any 타입을 사용할 수 있다.
function identity(arg: any): any {
return arg;
}
그러나 any 타입을 사용할 경우, 실제 함수가 받는 파라미터와 반환 값이 어떤 타입인지에 대한 정보를 모두 잃게 된다.
call signitures를 작성할 때, 들어올 확실한 타입을 모를 때 사용
이런 경우에 any 타입 대신 generic을 사용할 수 있다.
제네릭은 많은 도메인에서 <T> 또는 <V> 로 사용되지만 이름은 중요치 않다.
제네릭을 사용하기 위해서는 생성자를 호출하여 객체를 만들 때 T로 사용될 타입을 지정해주면 된다.
<T>(arr: T[]): T
※ T == 타입 변수 (Type variables) : 해당 클래스에서 사용할 수 있는 특정한 타입
function identity<Type>(arg: Type): Type {
return arg;
}
위의 함수에서 Type은 함수를 사용할 때 넘겨받은 인수의 타입을 캡처하고, 해당 타입 정보를 나중에 사용할 수 있게 한다.
제네릭 함수나 클래스에서는 두 개 이상의 타입 변수 사용 가능
function superPrint<T>(a: T[]): T {
return a[0]
}
const a = superPrint([1, 2, 3, 4])
const b = superPrint([true, false, true])
const c = superPrint(["a", "b", "c"])
const d = superPrint([1, 2, true, false, "hello"])
console.log(a, b, c, d) // 1 true 'a' 1
타입스크립트는 제네릭을 처음 인식했을 때와 제네릭의 순서를 기반으로 제네릭의 타입을 알게 된다.
function superPrint<T, M>(a: T[], b: M): T {
return a[0]
}
const a = superPrint([1, 2, 3, 4], 'x')
const b = superPrint([true, false, true], 1)
console.log(a, b) // 1 true
특정 타입들로만 동작하는 제네릭 함수
// ❌
function loggingIdentity<Type>(arg: Type): Type {
return arg.length
}
모든 타입이 length 프로퍼티를 갖지 않기 때문에 타입 경고가 발생한다.
length 프로퍼티가 있는 타입들에만 작동하도록 제한하고 싶다면 제약 조건을 추가해야 한다.
// 제약조건 명시하는 인터페이스
interface Lengthwise {
length: number
}
// 타입 변수는 기존에 사용하고 있는 타입 상속 가능
function loggingIdentity<Type extends Lengthwise>(arg: Type): Number {
return arg.length
}
'Typescript' 카테고리의 다른 글
어떤 상황에서 ==와 ===를 써야 할 것인가? (2) | 2024.11.20 |
---|---|
인덱스 시그니처 (0) | 2024.05.14 |
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type (0) | 2024.03.27 |
Type of emit value is always 'any' with new style defineEmits (0) | 2024.03.27 |
Typescript 인터페이스 네이밍 규칙 어떻게 할까? | 접두사 I를 사용하면 안 되는 이유 (1) | 2024.03.27 |