개발/TypeScript

[TypeScript] - Generic

Huni2397 2025. 4. 4. 16:06

typescript 하면서 기본적인 문법은 프로젝트를 하면서 익혔는데, 이번에 공부하면서 generic 에 대해서 한번 집고 가고싶어서 정리해보려고 합니다.

 

공식문서를 살펴보면 generic은 재사용 가능한 컴포넌트를 생성하는 도구상자의 주요 도구라고 합니다.

이 도구는 단일 타입이 아닌 다양한 타입에서 작동하는 컴포넌트를 만들 수 있다고 써있습니다.

 

그러니까 다양한 타입에서 사용할 수 있는 코드를 만들때 유용한 도구인 것입니다.

1. Generic Type

간단하게 예시를 만들어 보겠습니다.

먼저 generic을 사용하지 않았을 경우를 만들어보겠습니다.

function identityNumber(arg: number): number {
    return arg;
}

function identityString(arg: string): string {
    return arg;
}

function identityAny(arg: any): any {
    return arg;
}

 

이 identity 함수는 number, string, any에 따라서 분리가 되어 있지만 함수의 로직은 같으므로 이걸 컴포넌트화를 할 수 있을 것 같습니다.

// 보통 T를 많이 사용합니다.
// <> 를 통해 generic을 구현할 수 있습니다.

function identity<T>(arg: T): T {
    return arg;
}

identity(1)       // T : number
identity("123")   // T : string
identity([1,2,3]) // T : number[]

 

이렇게 T를 통해서 사용자가 준 인수의 타입을 통해 해당 함수의 type을 결정하고 사용할 수 있게 합니다.

위의 코드보다는 아래의 코드가 확실히 범용성 있는 코드라는 것을 알 수 있습니다.

 

// 호출 방법
// 1. 제네릭 표현으로 안해도 컴파일 할때 인수 추론을 통해 타입을 정함
let id = identity("huni")

// 2.
let id = identity<string>("huni")

 

2. Generic Class

다음으로는 Class에서의 generic을 살펴보겠습니다.

클래스 이름 뒤에 < > 를 통해 generic 타입 매개변수 목록을 가질 수 있습니다.

class GenericNumber<T> {
    zeroValue: T;
    add: (x: T, y: T) => T;
}

let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x + y; };

let stringNumeric = new GenericNumber<string>();
stringNumeric.zeroValue = "";
stringNumeric.add = function(x, y) { return x + y; };

 

※ Class 에서 static이 있는 값은 제네릭을 사용할 수 없습니다.

class MyClass<T> {
    static staticValue: T;  // 에러 발생
}

 

3. Generic Extends

보통 Extends는 확장의 의미를 가지고 있습니다. 하지만 generic에서는 확장이 아닌 제약의 의미로 사용됩니다.

interface나 type과 같이 쓰입니다.

// 1.
// 이게 없다면 T에 length 메소드 사용이 불가 하기 때문에 오류 발생
interface Lengthwise {
    length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
    console.log(arg.length)
    return arg;
}
loggingIdentity({length : 3);

// 2.
type Lengthwise = number | string;

function loggingIdentity<T extends Lengthwise>(arg: T): T {
    console.log(arg.length)
    return arg;
}

loggingIdentity(3);
loggingIdentity("3");

 

4. generic을 사용하는 이유?

처음에 소개했던 것과 같이 재사용성 있는 컴포넌트를 만들때 유용하다고 말씀 드렸습니다. 하지만 다른 이유는 뭐가 있을 지 소개해보겠습니다.

이렇게 사용하면 좋은 이유는 무엇일까요?

  • 코드의 재사용성이 증가한다.
  • 타입 안전성이 올라간다 -> 컴파일 시 타입을 검사하기 때문에 (any 는 런타임 까지 알 수 없음)
  • 어려 종류의 타입을 다룰 수 있는 유연성

 

참고자료

https://www.typescriptlang.org/docs/ : typescirpt 공식문서

https://buly.kr/E78d4Nz : inpa tistory