제네릭은 C#, Java 등의 언어에서 재사용성이 높은 컴포넌트를 만들 때 자주 활용되는 특징입니다.
특히, 한가지 타입보다 여러 가지 타입에서 동작하는 컴포넌트를 생성하는데 사용됩니다.
<T>
키워드 사용// JS 함수 사용 시
function logText(text){
console.log(text);
return text;
}
logText(10); // 숫자
logText('hello'); // 문자열
logText(true); // 진위값
// TS - 제네릭
function logText<T>(text: T):T{
console.log(text);
return text;
}
logText<string>('hello') // 함수를 호출할 때 파라미터에 대한 타입을 같이 지정하여 전달
logText<string>('hello') // 인자를 넘기는데 인자의 타입은 string
// 구조
function logText<T>(text: T):T{
console.log(text);
return text;
}
// 아래와 같이 동작 되는 것처럼 보인다.
function logText<string>(text: string):string{
console.log(text);
return text;
}
function logText(text: string){
console.log(text);
text.split('').reverse().join('');
return text;
}
logText('a');
logText(10);
logText(true);
split
이라는 문자열 API 를 사용하고 싶다는 가정function logNumber(num: number){
console.log(num);
return num;
}
logNumber(10);
function logText(text: string | number){
console.log(text);
text. // string 과 number 둘 다 접근 가능, 현재 타입은 string 과 number
return text;
}
const a = logText('a');
console.log(a) // 여전히 string 과 number 둘 다 가지고 있습니다.
a.split('') // 에러가 발생합니다.
logText(10);
text
의 타입은 string 과 number 둘 다 가지게 됩니다.split
API 를 사용할 수 없습니다. 결론적으로 a 는 string이 아니라 string | number
타입 입니다.function logText<T>(text: T): T{
console.log(text);
return text;
}
//const str = logText('a');
const str = logText<string>('a');
str.split(''); // 에러가 발생하지 않는다.
제네릭은 타입 정의에 대한 이점을 가져갑니다.
코드를 중복 선언 할 필요 없이 타입을 비워놓은 상태에서 타입에
어떤 타입이 들어갈지는 호출하는 시점에서 정의하는 것
또한 타입을 추론을 하여 최종 반환 값까지 붙일 수 있는 게 제네릭 입니다.
interface Dropdown{
value: string;
selected: boolean;
}
const obj: Dropdown = { value: `abc`, selected: false};
interface Dropdown<T>{
value: T;
selected: boolean;
}
const obj: Dropdown<string> = {value: 'abc', selected: false};
//const obj: Dropdown<Number> = {value: 'abc', selected: false}; // value 타입 에러 발생
function logTextLenght<T>(text: T): T {
console.log(text.length)
// 에러, 타입스크립트 입장에서는 logTextLenght에 어떤 타입이 들어올지 예측할 수 없기 때문에
// 개발자만 아는 사실
return text;
}
logTextLenght('hi');
function logTextLenght<T>(text: T[]): T[] {
// 함수 내부 안에서 배열임을 알 수 있다.
console.log(text.length)
text.forEach(function (text){
});
return text;
}
logTextLenght<string>(['hi', 'abc']);
interface LenghtType {
lenght: number;
}
function logTextLenght<T extends LenghtType>(text: T): T{
text.lenght;
return text;
}
logTextLenght(10); // 오류, 숫자는 `lengh` 가 제공 되지 않습니다.
logText({ length: 0, value: 'hi' }); // `text.length` 코드는 객체의 속성 접근과 같이 동작하므로 오류 없음
interface ShoppingItem {
name: string;
price: number;
stock: number;
}
// shoppingItem 에 있는 key 들 중에 한 가지가 제네릭이 된다.
// 즉, getShoppingItemOption 의 파라미터로는 'name', 'price', 'stock' 중 한 가지만 들어 갈 수 있다.
function getShoppingItemOption<T extends keyof ShoppingItem>(itemOption: T): T {
return itemOption;
}
getShoppingItemOption("name")
// getShoppingItemOption(10); // 에러 발생
// getShoppingItemOption<string>('a'); // 에러 발생