제네릭은 타입스크립트에서 재사용이 가능한 컴포넌트를 생성하는것을 도와주는 역할을 한다
문법
type A = <T>(a:T[]) => T
const a:A = (arr) => {
return arr[0]
}
const result= a([1,2,3])
const result2 = a(['1','2'])
// 함수형
function A<SomeGeneric>(arg:SomeGeneric) {}
A<Number>
A<String>
A<OurType>
// 클래스형
// !Static과 같은 정적변수는 제네릭으로 관리할 수 없다.
class A<T> {
constructor(a:T){}
}
new A<Number>(1)
new A<String>('a')
// 타입스크립트 인터페이스
interface GenericIdentityFn<Type> {
(arg: Type): Type;
}
주의점
- Static과 같은 정적변수는 제네릭으로 관리할 수 없다
- 아래와 같이 사용 시 extends에 해당되는 타입을 사용하지 않으면 에러가 발생합니다.
interface Lengthwise {
length: number;
}
function loggingIdentity<Type extends Lengthwise>(arg: Type): Type {
console.log(arg.length);
return arg;
}
하나의 함수에 아래 코드처럼 여러개의 Generic 타입지정도 가능하다.
function getFirstElem<T,U>(arr:T[],arr2:U[]) {
return arr[0]
}
예시
아래의 코드는 배열의 첫번째 인자를 반환해주는 코드이다. 제네릭을 사용하지 않는다면 아래와같이 모든 타입에 대해 함수를 만들어줘야만 타입 에러 없이 정상적으로 동작하게된다.
function getFirstNumElem(arr:number[]) {
return arr[0]
}
function getFirstStrElem(arr:string[]) {
return arr[0]
}
const numArr = [1,2,3]
const firstNum = getFirstNumElem(numArr)
const stringArr = ['1','2','3']
const firstStr = getFirstStrElem(stringArr)
물론 아래와 같이 argument 타입을 any타입으로 만들어 하나의 함수로도 사용할 수 있게 만들어줄수있다
function getFirstElem(arr:any[]) {
return arr[0]
}
// function getFirstStrElem(arr:string[]) {
// return arr[0]
// }
const numArr = [1,2,3]
const firstNum = getFirstElem(numArr)
const stringArr = ['1','2','3']
const firstStr = getFirstElem(stringArr)
하지만 이는 아래 이미지처럼 반환값 역시 any타입이 되는 문제가 발생하게된다.
함수를 이런식으로 바꾸면 되지 않을까?
function getFirstElem(arr:(number|string)[]) {
return arr[0]
}
이러한 방법 역시 아래와 같은 문제가 발생한다.
혹은 argument의 타입이 늘어나면 늘어날수록 이러한 방식은 의미가 없어지게 된다.
이러할 때 사용할수 있는것이 타입스크립트의 제네릭 타입이다.
function getFirstElem<T>(arr:T[]) {
return arr[0]
}
const numArr = [1,2,3]
const firstNum = getFirstElem<number>(numArr)
const stringArr = ['1','2','3']
const firstStr = getFirstElem<string>(stringArr)
위와 같이 사용 시 T를 Number 혹은 String과 같이 명시적으로 타입을 지정하여 return 타입 역시 해당 타입에 맞는 타입으로 할당되게된다.
물론 아래 코드와 같이 암시적으로도 generic 타입을 사용할 수 있다.
const numArr = [1,2,3]
const firstNum = getFirstElem(numArr)
const stringArr = ['1','2','3']
const firstStr = getFirstElem(stringArr)
사용
- javascript 기본 객체
[제네릭 적용 전]
[제네릭 적용 후]
- React
[제네릭 적용 전]
[제네릭 적용 후]
추가
Default Value
아래 코드처럼 기본 값을 넣어줄 수 있습니다. 만약 ApiResponse 호출시에 아무 제네릭 타입도 지정하지 않는다면 에러가 나지만 아래와 같이 기본값을 넣어주면 제네릭 타입을 지정하지 않더라도 기본 타입이 status:number타입이 되게 됩니다.
type ApiResponse<Data = {status:number}> = {
data:Data
isError:boolean
}
type TempResposne = ApiResponse
[적용 이전]
[적용 이후]
Extends
extends로 사용 가능한 타입을 제한할 수 있습니다. 아래 코드처럼 extends object로 타입을 제한하면 object 타입이 포함된 타입만 제네릭 지정이 가능하게됩니다.
type ApiResponse<Data extends object> = {
data:Data
isError:boolean
}
type TempResposne = ApiResponse<number>
[적용 이전]
[적용 이후]
'typescript' 카테고리의 다른 글
TypeScript 컴파일러에서의 진단 로직 (2) | 2024.07.24 |
---|---|
타입 스크립트 5.5 업데이트 모든 내용 요약 (3) | 2024.07.22 |
타입스크립트에서 타입 호환성은 어떻게 체크되는가? (1) | 2024.03.13 |