제네릭(Generics)이란 타입 을 함수의 파라미터처럼 사용하는 것 을 의미한다.
🔍 자바스크립트에서는 다음과 같이 코드를 작성했다.
function getNum(num) {
return num;
}
=> 위 함수는 이름으로보나 변수명으로 보나 number를 받아 number를 리턴하는 함수같지만, 사실 num에 어떤값을 넘겨줘도 그 값을 그대~~로 반환한다.
getNum(1) // 1
getNum('모야 숫자라면서여') // '모야 숫자라면서여'
getNum([1,2,3]) // [1,2,3]
그렇다면 타입스크립트에서도 이렇게 할 수 없을까? 🤔 타입스크립트에서는 타입을 꼭 지정해줘야 하는디...(물론 any 사용 말고. any는 타입을 검사하지 않는 문제점이 있다.)
이러한 관점에서 나온게 바로 제네릭이다. getNum은 제네릭을 적용해서 다음과 같이 작성할 수 있다.
function getNum<T>(num:T):T {
return num;
}
getNum<number>(1)
getNum<number>('숫자인가여?')
와 같이 작성하면 다음과 같은 오류가 보인다.
물론 다음과 같이 사용할 수도 있다.
getNum<string>('문자에여!')
제네릭을 사용하면, 타입 추론으로 자바스크립트 문법처럼 작성할 수 있다.
getNum(1)
이를 통해, getNum<number>
는 다음과 같음을 알 수 있다.
function getNum (num:number) :number {
return num
}
물론 any를 사용해도 '작동하기는' 한다.
function getNum (num:any) :any {
return num
}
getNum(1)
를 하면 1을 리턴한다. 그러나 우리가 받고 싶은건 number임에도 불구하고, any로 인해서 무엇이 전달인자로 들어갔는지, 무엇이 나오는지 알 수 없게된다. 즉, 타입스크립트가 실시하는 검사의 도움을 받을 수 없게 되는 것이다!
예를들어,
function getNum2 (num:any) :any {
return num.length
}
라는 함수의 경우, getNum2(2)
를 해도 함수가 에러를 표시하지 않는다.
따라서 전에 말했듯이 ❗️any는 되도록이면 사용을 지양하는것이 좋다!
type GetNum = {
<T>(num:T):T
}
const getNum:GetNum = (num) => {
return num
}
type을 사용해서 작성할수도 있다. 와~. 타입스크립트의 타입 추론 기능을 사용하는것이 좋기에, 이 방법이 추천된다~! 코드 복잡해져서 이렇게 사용하기 힘들면 그냥 바로 제네릭 작성하시고~
type People<T> = {
age:number,
parents:{
mother: string,
father: string,
}
childs: T
}
type Childs = {
child: number
}
type Family = People<Childs>
const hyeonsu:Family = {
age:28,
parents:{
mother: 'mother',
father: 'father',
},
childs: {
child:0
}
}
이런 식으로 타입의 확장이 가능하다. 타입 Childs
를 만들고, 이를 People
에 넣어서 새로운 타입 Family
를 만들었다. 여기에 더해서
const you:People<null> = {
age:22,
parents:{
mother: 'mother',
father: 'father',
},
childs:null
}
이런식으로 childs
값이 없는 you
변수를 만들 수도 있다.