제네릭이란 타입을 마치 함수의 파마리터처럼 사용하는 것을 말한다.
함수를 호출할 대 넘긴 타입에 대해 타입스크립트가 추정할 수 있다. 따라서 함수의 입력 값
에 대한 타입과 출력 값
에 대한 타입이 동일한지 검증할 수 있다.
제네릭을 사용하면 컴파일러에서 인자에 타입을 넣어달라는 경고를 볼 수 있다.
function logText<T>(text: T): T {
return text;
}
만약에 여기서 함수의 인자로 받은 값의 length
를 확인하고 싶다면?
function logText<T>(text: T): T {
console.log(text.length); //에러
return text;
}
위 코드에서 컴파일러는 에러
를 발생시킨다.
왜냐하면 text에 .length
가 있다는 단서는 없기 때문이다.
인자와 반환 값에 대한 타입
을 정하진 않았지만, 입력 값으로 어떤 타입이 들어왔고 반환 값으로 어떤 타입이 나가는지 알 수 있다.
그래서 이런 경우에는 아래와 같이 제네릭에 타입을 줄 수가 있다.
function logText<T>(text: T[]): T[]{
console.log(text.length);
}
T[]
형태로 제네릭 타입이 배열이기 때문에 length
를 허용한다.
function getText<T>(text: T):T{
return text;
}
getText<string>("hi");
getText<number>(10);
getText<boolean>(true);
//호출할 때
const text = getText<string>("hi");
//또는
const text = getText("hi");
함수를 호출할 때 위와 같이 함수 안에서 사용할 타입을 넘겨줄 수 있다.
function 함수<T>(x:T):T{
return x - 1 ///에러
}
let a = 함수<number>(100)
위와 같이 에러가 나는 이유는 <T>
자리에 number말고 string이 들어올 수도 있어서 -1
과 같은 연산을 미리 방지하는 것이다.
이것을 해결하기 위해서는 extends
문법을 사용한다.
function 함수<T extends number>(x:T):T{
return x - 1 /// 99
}
let a = 함수<number>(100)
interface check{
length : number
}
function 함수<T extends check>(x :T):T{
return x.length
}
let a = 함수<string>("hello") ///가능
let a = 함수<number>(1234) ///에러남
length 속성을 가지고 있는 타입을 인터페이스로 생성했다. 그리고 extends
를 해주면 T는 length:number라는 타입을 복사해서 갖게된다.