TS - TIL(4)

돌리의 하루·2023년 6월 28일
0

제네릭

아래와 같은 함수가 있다고 해보자

function printLog(text) {
	return text;
}

파라미터로 text를 받는 함수 printLog는 반환값으로 text를 리턴하고 있다.

이 함수를 제네릭이 있을때와 없을때 코드를 비교해서 구현해보자!

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

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

text에 string 외의 다른 값이 들어오면 컴파일 에러가 난다.

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

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

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

위의 상황을 방지하기 위해서는 이렇게 각각 파라미터 text가 다른 타입으로 들어가는 함수를 만들면 된다.

그러나 이렇게 되면 코드가 반복적이고 유지보수에 좋아보이지 않는다.

그렇다면 유니온을 쓰는 방법은 어떨까?

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

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

유니온은 들어가는 인수는 해결이 되지만, 함수 내에서 결국 string 과 number가 둘 다 접근할 수 있는 api를 제공한다.

제네릭을 이용한다면?

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

pringLog에 T라는 변수를 추가한 제네릭.
T는 유저가 준 파라미터의 타입을 캡처하고, 이 정보를 나중에 사용할 수 있게 한다.

const str = printLog<string>('hello');

함수를 호출할 때 인수 중 하나로 T를 string으로 명시하고 타입 주변을 <>로 감싸준다.

이 방법 말고도, 타입 추론 기능을 활용하면 아래와 같이 작성할 수 있다.

const str = printLog('hello');

하지만 위의 방법은 타입이 복잡해져서 컴파일러가 타입을 유추할 수 없게 되는 경우에는 사용할 수 없다.


인터페이스 & 제네릭

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

위와 같은 제네릭 interface에는 name의 값으로 어떤 타입이 들어갈지 작성해주면, 인터페이스를 여러개 만들지 않고도 재사용할 수 있다.

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

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

제네릭 타입 변수

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

위의 함수는 T에 string이 들어갈지, number가 들어갈지 모르기때문에,
text.length를 작성하게 되면 컴파일 에러가 난다.

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

위와 같이 제네릭에 타입을 주게되면, 유연하게 함수의 타입을 정의해줄 수 있다.

이 때 제네릭함수는 T라는 변수 타입을 받고, 인자 값으로는 배열 형태의 T를 받는다.

제네릭 타입은 배열이기 때문에, .length를 허용하게 된다.

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

이렇게 더욱 더 명시적으로도 사용 가능하다.

profile
진화중인 돌리입니다 :>

0개의 댓글