본문 바로가기
🟨 JavaScript 🟨/🟦TypeScript🟦

TypeScript - Function과 Generics(제네릭 타입)

by 백씨네 2023. 4. 20.
728x90

목차

1. Function 

2. Generics (제네릭)

3. 다양한 타입의 객체

4. Function overloading VS Generics

 

 

 

1. Function 

함수에 대한 데이터 타입을 지정할 때, 함수의 반환값뿐 아니라, 매개변수에도 데이터 타입이 지정되어 있어야 한다.

 

// 함수 선언식
function add(x: number, y: number): number {
    return x + y
}
//함수 표현식
const ad2 = function (x: number, y: number): number {
    return x + y
}
//화살표 함수
const add3 = (x: number, y: number): number => x + y

 

1-1. 매개변수의 여러 타입

한 가지 매개변수에 대해서 매개변수가 있을 수 있고, 없을 수도 있는 상황이 있다. 이때 매개변수를 |(or연산자)를 통해서 2가지 타입을 지정해줄 수 있다.

hello 함수를 호출 할 때, 매개변수가 있거나, 없을 수 있는 함수를 만든다면, 매개변수의 타입을 잘 지정해야 한다.

 

{
    //방법 1
    //매개변수를 name: string = '' 이렇게 적어도 된다.
    const hello = (name: string | null = null): void => {
        if (name) {
            console.log(name.length)
            console.log(`hello ${name}`)
        } else {
            console.log("hello ")
        }
    }
}

{
    //방법 2
    const hello = (name?: string): void => {
        if (name) {
            console.log(name.length)
            console.log(`hello ${name}`)
        } else {
            console.log("hello ")
        }
    }
}

hello()
hello("baekspace")

 

1-2. 함수 오버로딩 (function overloading)

Ex) 123->321 or 'abc'->'cba'로 만들고 싶다.

const reverseVari = (vari: string | number): string | number => {
    if (typeof vari === "string") {
        console.log(vari.split("").reverse().join(""))
        return vari.split("").reverse().join("")
    } else {
        console.log(parseInt(vari.toString().split("").reverse().join("")))
        return parseInt(vari.toString().split("").reverse().join(""))
    }
}
reverseVari("abc")
reverseVari(123)

일반적으로 이런 로직을 통해서 진행을 할 것이다. 하지만 이 코드에는 문제점이 있는데,

리턴값이 2가지 종류이기 때문에 원하는 대로 데이터 타입을 추론할 수 없다. 그래서 매개변수가 string이면 반환값이 string , number이면 반환값이 number로 정확하게 지정해야 한다.

이때 해결할 수 있는 방법이 '함수 오버로딩'이다.

 

아래는 함수 오버로딩의 대한 예시 코드이다.

//함수 선언식을 이용한 함수 오버로딩
function reverseVari(x: number): number
function reverseVari(x: string): string
function reverseVari(x: number | string): number | string {
    const res = x.toString().split("").reverse().join("")
    return typeof x === "number" ? parseInt(res) : res
}

const result = reverseVari("123")

// 화살표 함수을 이용한 함수 오버로딩
type ReverseFunction = {
    (x: number): number
    (x: string): string
}

const reverse = ((x: string | number) => {
    const res = x.toString().split("").reverse().join("")
    return typeof x === "number" ? parseInt(res) : res
}) as ReverseFunction

const result1 = reverse(123) // return 321 (number)
const result2 = reverse("hello")

 

 

 

 

2. Generics (제네릭)

확장성이 좋은 코드를 작성하게 된다면 매개변수의 타입에 따라서 반환값의 타입도 똑같이 지정하고 싶은 경우가 있다.

ex)
매개변수 number -> return값 number,
매개변수 string -> return값 string,
매개변수 object -> return값 object,
매개변수 array -> return값 array,

이때 사용할 수 있는 방법이 Generics type이다.

 

//기본 문법
const echo = <T>(a: T): T => {
    console.log(a)
    return a
}

echo(1)
echo("a")
echo({ name: "abc" })
echo(["123"])

 

T는 타입에 대한 매개변수를 뜻한다. 

 

2-1. 함수의 제네릭

interface와 제네릭을 같이 쓸 때, 함수 실행을 하면서 interface로 지정한 타입을 타입의 매개변수에 같이 전달할 수 있다.

 

interface Props {
    name: string
    id: string
}
const echo = <T>(a: T): T => {
    console.log(a)
    return a
}
const props: Props = {
    name: "baek",
    id: "baekspacee",
}

echo<Props>(props)

 

echo 함수를 호출할 때 "<Props>"에 의해서 타입의 매개변수 T가 Props 인터페이스로 지정되고, 반환 값의 데이터 타입도 Props 인터페이스로 지정되었다.

 

2-2. 반환값이 배열인 함수의 제네릭

Array의 경우 매개변수의 타입뿐 아니라 매개변수 안에 있는 요소의 타입도 지정해주어야 한다.
ex) "string []" or "number []"

이 때도 제네릭을 이용하면 쉽게 지정할 수 있다.

 

const push = <T>(a: T): T[] => {
    const result = [a]
    console.log(result)
    return result
}
push(1)
push("asdf")

 

 

 

3. 다양한 타입의 객체

interface A {
    name: string
}
interface B {
    age: number
}
interface C {
    weight: number
}

const a: A = { name: "baekspace" }
const b: B = { age: 30 }
const c: C = { weight: 75 }

const object = <T>(value: T): T => {
    return value
}

console.log(object<A>(a).name)
console.log(object<B>(b).age)
console.log(object<C>(c).weight)

 

object로 타입은 object안에 배열, 객체가 포함된 상위의 개념이기 때문에 데이터 타입을 제대로 추론하지 못하게 된다.

 

하지만 제네릭을 이용해서 매개변수로 데이터타입을 지정하게 된다면 호출했을 때 데이터타입을 추론할 수 있어서 해당 인터페이스에 정의된 프로퍼티에 접근이 가능하고 그 데이터 타입의 메서드를 사용할 수 있게 된다.

 

 

 

 

4. Function overloading VS Generics

유사점 :


1. 서로 다른 데이터 타입을 처리할 수 있는 코드를 작성할 수 있게 한다.
2. 입력과 출력에 대한 타입이 지정되므로 타입을 추론할 수 있게 해 준다.

차이점 :


오버로딩은 이름이 같은 함수의 매개변수의 타입과 반환 값의 데이터 타입을 여러 개 지정할 때 사용할 수 있지만

제네릭은 단일 함수, 데이터를 다양한 타입의 데이터로 조작할 때 사용할 수 코드를 만들 수 있다.

 

 

 

 


반응형

댓글