TypeScript 중급

TypeScript 제네릭

제네릭은 타입스크립트의 강력한 기능 중 하나입니다. 상자에 물건을 넣고 빼는 것처럼, 제네릭을 사용하면 다양한 타입을 다룰 수 있습니다. 이 튜토리얼에서는 제네릭의 개념과 핵심 기능을 살펴보고, 간단한 예제를 통해 이해를 돕겠습니다.

개념소개

제네릭은 함수, 클래스, 인터페이스 등에서 재사용 가능한 코드를 작성할 때 유용합니다. 제네릭을 사용하면, 타입을 매개변수로 전달할 수 있어 동일한 코드를 다양한 타입에 대해 사용할 수 있습니다. 이를 통해 코드의 중복을 줄이고 유지보수를 용이하게 할 수 있습니다. 

제네릭이 없을 때 

아래 코드는 a, b를 담은 배열을 만듭니다.  

function contain(a, b){
    return [a,b]
}

타입 안정성을 위해서 함수의 데이터 타입을 정의해봅시다. 

function containNum(a:number, b:number):number[]{
    return [a,b];
}

이제 함수가 좀 더 안전해졌습니다. 어?! 그런데 배열의 원소로 문자를 사용해야 할 때도 있다고 쳐봅시다. 

function containString(a:string, b:string):string[]{
    return [a,b];
}

이런식으로 여러 데이터 타입을 받아야 하는 상황이라면 그 때마다 함수를 또 만들어야 할 것입니다.

Union 연산자를 사용하면 이런 문제를 조금 완화할 수 있습니다만, 완전한 해결책은 아닙니다. 

function containNumberString(a:number|string, b:number|string):(number|string)[]{
    return [a,b]
}

제네릭 등장!

이때 사용하는 것이 제네릭입니다. 

function containGeneric<T>(a:T, b:T):T[]{
    return [a,b]
}

위의 함수를 호출해보겠습니다. 

console.log(containGeneric<number>(1,1));

containGeneric 함수의 T 의 데이터 타입은 이제부터 number가 됩니다. 그 결과 위의 코드는 아래와 같은 의미를 갖게 됩니다. T는 관습적으로 사용하는 이름일 뿐입니다. 어떤 이름을 사용해도 됩니다. 

function containGeneric(a:number, b:number):number[]{
    return [a,b]
}

만약 아래와 같은 코드가 있다면 에러가 나겠죠. 

console.log(containGeneric<number>('a','b'));

이 처럼 제네릭은 타입을 규제하면서도 그 규제 내용을 유연하게 변경할 수 있도록 허용하는 문법이라고 할 수 있습니다. 

제네릭의 생략

제네릭은 생략할 수 있습니다. 아래의 코드는 T의 데이터 타입을 지정하지 않았습니다.하지만 TypeScript는 a와 b의 데이터 타입을 바탕으로 T의 타입을 추론했기 때문에 아래의 코드는 에러가 발생하지 않습니다.

console.log(containGeneric(1,1)); // ok

반면에 아래 코드는 a의 T는 number와 b의 T는 string이리 때문에 오류가 발생합니다. 

console.log(containGeneric(1,'b')); // error

여러개의 제네릭

여러개의 제네릭을 사용할 수도 있습니다. 

function containGeneric<T, U>(a: T, b: U): [T, U] {
  return [a, b];
}

const result = containGeneric<number, string>(1, 'two');

타입 별칭 (Type Aliases)

type Container<T> = { value: T };

const stringContainer: Container<string> = { value: 'Hello' };
const numberContainer: Container<number> = { value: 42 };
console.log(stringContainer.value); // 출력: Hello
console.log(numberContainer.value); // 출력: 42
// 제네릭 타입 T를 사용하여 값이 포함된 컨테이너 타입을 정의

다루지 않은 내용

  • 인터페이스에 제네릭 적용
  • 클래스에 제네릭 적용
  • 타입 별칭에 제네릭 적용

댓글

댓글 본문
버전 관리
egoing
현재 버전
선택 버전
graphittie 자세히 보기