TypeScript 공부(8)

김희목·2024년 8월 27일
0

패스트캠퍼스

목록 보기
51/53

제네릭(Generic)

타입스크립트의 제네릭(Generics)은 코드의 재사용성을 높이고, 다양한 타입을 처리할 수 있도록 해주는 강력한 기능입니다. 제네릭을 사용하면 코드에서 타입을 명시적으로 지정하지 않고, 코드가 실행될 때 타입을 지정할 수 있습니다. 제네릭은 함수, 클래스, 인터페이스에서 모두 사용할 수 있습니다. 각 경우에 대해 설명드리겠습니다.

함수

interface Obj {
  x: number
}
type Arr = [number, number] // 튜플타입

function toArray(a: string, b: string): string[]
function toArray(a: number, b: number): number[]
function toArray(a: boolean, b: boolean): boolean[]
function toArray(a: Obj, b: Obj): Obj[]
function toArray(a: Arr, b: Arr): Arr[]
function toArray(a: any, b: any) {
  return [a,b]
} // 함수 오버로딩 

console.log(
  toArray('Neo', 'Anderson'),
  toArray(1,2),
  toArray(true, false),
  toArray({x:1}, {x: 2}),
  toArray([1,2],[3,4])
)

현재 코드를 보면 함수 오버로딩 기법을 사용하여 여러가지의 타입을 출력하는 코드입니다. 하지만 타입이 추가될 때마다 함수 오버로딩 기법을 추가해야하는데, 이러한 코드에서 제네릭 문법을 통해서 이 코드의 내용을 개선해 줄 수 있는데 그부분을 한번 확인해 보겠습니다.

interface Obj {
  x: number
}
type Arr = [number, number]

function toArray<T>(a: T, b: T) {
  return [a,b]
}

console.log(
  toArray('Neo', 'Anderson'),
  toArray(1,2),
  toArray(true, false),
  toArray({x:1}, {x: 2}),
  toArray([1,2],[3,4])
)

해당 코드를 살펴보면 오버로딩 기법은 다 없어지고, toArray부분에 T라는 <> 안에 들어있는 값이 추가되고, a와 b의 값도 T로 설정이 되어있습니다. 이부분에서 콘솔로그로 출력되는 부분에서 오류가 발생하지 않는데 그 이유는 제네릭 문법을 통해서 T라는 알 수 없었던 타입이 함수가 호출되었을 때 첫번째 인수의 타입으로 정해지게 됩니다.

그래서 첫번째 console.log의 Neo와 Anderson은 string 타입이므로, T의 타입이 string 타입이 되게 됩니다.

혹은 console.log에서 호출을 할때 아래 코드 형식으로 설정해줘도 됩니다.

console.log(
  toArray<string>('Neo', 'Anderson'),
  toArray<number>(1,2),
  toArray<boolean>(true, false),
  toArray<Obj>({x:1}, {x: 2}),
  toArray<Arr>([1,2],[3,4])
)

클래스

class User<P> {
  constructor(public payload: P) {}
  getPayload() {
    return this.payload
  }
}

interface UserAType {
  name: string
  age: number
  isValid: boolean
}
interface UserBType {
  name: string
  age: number
  emails: string[]
}

const heropy = new User<UserAType>({
  name: 'Heropy',
  age: 85,
  isValid: true
})
const neo = new User<UserBType>({
  name: 'Neo',
  age: 22,
  emails: ['neo@gmail.com']
})

마찬가지로 클래스에서도 클래스를 호출하고, interface 타입을 꺽쇠괄호로 호출을 해주면, 타입을 선언해줄 수 있습니다.

인터페이스

interface MyData<T> {
  name: string
  value: T
}

const dataA: MyData<string> = {
  name: 'Data A',
  value: 'Hello world'
}
const dataB: MyData<number> = {
  name: 'Data B',
  value: 1234
}
const dataC: MyData<boolean> = {
  name: 'Data C',
  value: true
}
const dataD: MyData<number[]> = {
  name: 'Data D',
  value: [1,2,3,4]
}

인터페이스에서도 인터페이스를 작성해주고, 꺽쇠괄호를 통해 T라는 값을 변수로 지정해준 후, 아래 const로 변수를 만들어주고 인터페이스를 호출한뒤, 해당 변수에서 사용할 타입을 꺽쇠괄호로 호출을 해주면 됩니다.

제약 조건(Constraints)

제약조건이란, 위에 코드에서는 T라는 값으로 입력받는 값을 타입으로 지정해주는 제네릭문법을 사용하고 있는데, 여기서 T라는 값의 타입을 만약 string,number 이 두 타입으로만 제한을 하고 싶을 경우에 사용하게 됩니다.

interface MyData<T extends string | number> {
  name: string
  value: T
}

이렇게 T라는 변수가 string,number 즉 두가지의 유니온 타입을 상속받도록 지정해주어서 제약조건을 걸 수 있습니다.

0개의 댓글