TypeScript의 제네릭(Generic)

Taehye.on·2023년 6월 2일
0

코드스테이츠 44기

목록 보기
82/89
post-thumbnail

D-65

🔍 TypeScript의 제네릭(Generic)

제네릭(Generic)은 코드 재사용성을 높이고 타입 안정성을 보장하는 기능이다. 제네릭 사용으로 함수나 클래스를 작성할 때, 사용될 데이터 타입을 미리 지정하지 않고, 이후에 함수나 클래스를 호출할 때 인자로 전달된 데이터의 타입에 따라 자동으로 타입을 추론하게 된다.


function printLog(text) {
  return text;
}

위 함수는 파라미터로 text를 받고 반환 값으로 text를 리턴하고 있다. 이를 제네릭 없이 구현해보면 아래와 같다

function printLog(text: string): string {
  return text;
}

printLog('hello'); // 정상
printLog(123); // 에러

첫번째 함수는 printLog함수에 특정 타입을 작성한 코드다. 명시된 타입인 string타입 외에 다른 타입이 들어오면 컴파일 에러가 난다.

이를 해결하기 위해 중복으로 함수를 선언하는 방법이 있다.

function printLog(text: string): string {
 return text;
}

function printLogNumber(text: number): number {
 return text;
}

printLog('hello'); // 정상
printLogNumber(123); // 정상

여기서 |연산자를 이용해 유니온 타입으로 선언할 수 있다.

function printLog(text: string | number) {
  return text;
}

printLog('hello'); // 정상
printLogNumber(123); // 정상

any타입을 사용한 코드는 어떤 타입이든 받을 수 있지만 실제 함수가 반환할 때 어떤 타입인지 추론할 수 없게 된다.

function printLog(text: any): any {
  return text;
}

이 때 제네릭을 사용할 필요가 생긴다.


🔍 제네릭(Generic)

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

printLog함수에 T라는 타입 변수를 추가해 유저가 준 파라미터의 타입을 캡처하고 이 정보를 나중에 사용할 수 있게 한다. 여기서 T를 반환 타입으로 다시 사용한다.

📌 인터페이스와 제네릭

interface Item<T> {
  name: T;
  stock: number;
  selected: boolean;
}

Item인터페이스를 사용해 만든 객체는 name값으로 어떤 타입인지 작성해 준다면 재사용 가능하다.

const obj: Item<string> = { 
	name: "T-shirts",
	stock: 2, 
	selected: false
};

const obj: Item<number> = { 
	name: 2044512,
	stock: 2, 
	selected: false
};

이처럼 여러 개의 객체를 만들어 재사용 가능하다.

📌 클래스와 제네릭

TypeScript에서 팩토리를 생성할 때 생성자 함수로 클래스 타입을 참조해야한다.

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; };

📌 제네릭 타입 변수

제네릭 함수를 만들 때 컴파일러가 함수 본문에 제네릭 타입화된 매개변수를 쓰도록 강요한다.

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

이처럼 console.log(text.length);를 작성할 경우 컴파일 에러가 난다. 개발자가 string 타입이 아닌 number 타입을 보낼 수도 있기 때문에, T에는 .length가 있다는 것을 추론할 수 없다.

이때 제네릭에 타입을 줘 유연하게 함수의 타입을 정의해 줄 수 있다.

function printLog<T>(text: T[]): T[] {
	console.log(text.length);
	return text;
}

// or
function printLog<T>(text: Array<T>): Array<T> {
	console.log(text.length);
	return text;
}

T라는 변수 타입을 받고, 인자 값으로는 배열 형태의 T를 받는 코드다.
이 경우 제네릭 타입이 배열이기 때문에 .length를 허용한다.

0개의 댓글