본문 바로가기
프로그래밍/typescsript

타입스크립트의 Generic(제네릭)

by 한코코 2022. 11. 23.

Generic(제네릭)이란?

C#이나 JAVA 등 언어에서 제네릭은 재사용성이 높은 컴포넌트를 만들때 자주 활용되는 특징이며, 한가지 타입보다 여러가지 타입에서 동작하는 컴포넌트를 생성하는데 사용된다. 타입스크립트에서 제네릭이란 타입을 마치 함수의 파라미터처럼 사용하는 것을 의미한다.

// 어떠한 타입이라도 넣을 수 있고, 그와 같은 타입으로 return 값을 지정하는 코드
function getText<T>(text: T): T { return text;}

getText<string>('hi');
getText<number>(10);
getText<boolean>(true);

제네릭을 위 코드처럼 사용함으로서 어떤 타입이던지 복잡하게 |을 쓰지않고도 사용할 수 있다.

 

 

 

제네릭 타입 변수

우선 T라는 변수 타입을 받고, 인자값으로는 배열형태의 T를 받는 코드다.

예) [1,2,3]같은 배열을 받으면 반환값으로 number를 돌려줌.

function logText<T>(text: T[]): T[] {
  console.log(text.length); // 제네릭 타입이 배열이기 때문에 `length`를 허용합니다.
  return text;
}

// 같은 내용이지만 좀더 명시적으로 작성한 코드
function logText<T>(text: Array<T>): Array<T> {
  console.log(text.length);
  return text;
}

 

 

 

제네릭 타입 간략화

다음 #1과 #2는 같은 기능을 하는 코드다. #2가 좀더 단순화되어있다.

function logText<T>(text: T): T { return text; }

let str: <T>(text: T) => T = logText; // #1
let str: {<T>(text: T): T} = logText; // #2

이처럼 제네릭 인터페이스 코드를 다음과 같이 작성할 수 있다.

function logText<T>(text: T): T { return text; }

interface GenericLogTextFn { <T>(text: T): T; }
let myString: GenericLogTextFn = logText;

interface GenericLogTextFn<T> { (text: T): T; } // 인자타입 강조
let myString: GenericLogTextFn<string> = logText;

 

 

 

제네릭 클래스

제네릭 인터페이스와 비슷하게 사용하면 되는 제네릭 클래스.

단, 제네릭 클래스는 정적 측면이 아닌 인스턴스 측면에서만 제네릭이므로 클래스로 작업할때 정적 멤버는 클래스의 유형 매개변수를 사용할 수 없다.

class GenericMath<T> {
  pi: T;
  sum: (x: T, y: T) => T;
}

let math = new GenericMath<number>();

 

 

 

제네릭 제약 조건

앞에서 제네릭 타입 변수에서 살펴본 내용 말고도 제네릭 함수에 어느 정도 타입 힌트를 줄 수 있는 방법이 있다.

해당 타입을 정의하지 않고도 length 속성 정도는 허용하려면 아래와 같이 작성한다.

interface LengthWise {
  length: number;
}

function logText<T extends LengthWise>(text: T): T {
  console.log(text.length);
  return text;
}

// Error, 숫자 타입에는 `length`가 존재하지 않으므로 오류 발생
logText(10);

// `text.length` 코드는 객체의 속성 접근과 같이 동작하므로 오류 없음
logText({ length: 0, value: 'hi' });

 

 

객체의 속성을 제약하는 방법

두 객체를 비교할 때도 제네릭 제약 조건을 사용할 수 있다.

제네릭을 선언할 때 <O extends keyof T> 부분에서 첫 번째 인자로 받는 객체에 없는 속성들은 접근할 수 없게끔 제한한 코드

function getProperty<T, O extends keyof T>(obj: T, key: O) {
  return obj[key];  
}
let obj = { a: 1, b: 2, c: 3 };

getProperty(obj, "a"); // okay
getProperty(obj, "z"); // error: "z"는 "a", "b", "c" 속성에 해당하지 않습니다.

 

 

참고 사이트 : 타입스크립트 핸드북

댓글