👶 TypeScript

제네릭을 어디에 선언할 수 있을까?

개발자 린다씨 2023. 1. 13. 10:00
반응형

제네릭을 어디에 선언할 수 있을까?

TypeScript에선 호출 시그니처를 정의하는 방법에 따라 제네릭을 추가하는 방법이 정해져 있습니다.

type Filter = {<T>(array: T[], f: (item: T) => boolean) =>T[]} // ①
let filter: Filter = //...

type Filter<T> = { // ②
    (array: T[], f: (item:T) => boolean): T[]
}
let filter: Filter<number> = // ...

type Filter = <T>(array: T[], f: (item: T) => boolean) => T[] // ③
let filter: Filter = // ...

type Filter<T> = (array: T[], f: (item: T) => boolean) => T[] // ④
let filter: Filter<string> = // ...

function filter<T>(array: T[], f: (item: T) => boolean): T[]{ // ⑤
    // ...
}

T의 범위를 개별 시그니처로 한정한 전체 호출 시그니처입니다. T를 한 시그니처 범위로 한정했으므로 TypeScript는 filter 타입의 함수를 호출할 때 이 시그니처의 T를 구체 타입으로 한정합니다. 각각의 filter 호출은 자신만의 T 한정 값을 갖습니다.

 

T의 범위를 모든 시그니처로 한정한 전체 호출 시그니처입니다. T를 Filter 타입의 일부로 선언했으므로 TypeScript는 Filter 타입의 함수를 선언할 때 T를 한정합니다.

 

과 비슷하지만 전체 시그니처가 아니라 단축 호출 시그니처입니다.

 

와 비슷하지만 전체 시그니처가 아니라 단축 호출 시그니처입니다.

 

T를 시그니처 범위로 한정한, 이름을 갖는 함수 호출 시그니처입니다. filter를 호출할 때 T타입으로 한정하므로 각 filter 호출은 자신만의 T 한정 값을 갖습니다.

 

두 번째 예로 map 함수를 구현해 보겠습니다.

 

map은 filter와 비슷하지만 배열에서 항목을 제거하는 대신 매핑 함수를 이용하여 각 항목을 변환합니다.

 

구현부터 시작하겠습니다.

function map(array: unknown[], f: (item: unknown) => unknown): unknown[] {
    let result = []
    for (let i = 0; i < array.length; i++){
        result[i] = f(array[i])
    }
    return result
}

 

위의 코드를 제네릭으로 변환하면 아래와 같습니다.

function map<T,U>(array: T[], f: (item: T) => U): U[] {
    let result = []
    for (let i = 0; i < array.length; i++){
        result[i] = f(array[i])
    }
    return result
}

인수 배열 멤버의 타입을 대변하는 T, 반환 배열 멤버 타입을 대변하는 U, 이렇게 두 가지 제네릭 타입이 필요합니다.

 

T타입의 요소를 포함하는 배열을 전달하면 매핑 함수가 T 타입의 값을 가지고 U 타입의 값으로 변환합니다.

 

그리고 최종적으로 U 타입의 항목을 포함하는 배열을 반환합니다.

반응형