IT/TypeScript

[TypeScript] call signatures/overloading/generics

Huitopia 2024. 1. 12. 02:57
728x90

call signatures

코드에 마우스 올리면 나온다.

Call(=Function) Signature란 함수의 매개변수와 반환 값의 타입을 모두 type으로 미리 선언하는 것이다.

타입을 만들고 함수가 어떻게 작동하는 지 서술 가능하다.

// 기존 함수
const add = (a:number, b:number) => a+b

// 함수의 call signature 타입 생성
type Add = (a:number, b:number) => number;

// 위에 타입 지정으로 타입이 number라 선언 안 해도 됨
const add2:Add = (a,b) => a+b

// 함수의 call signature 길게 작성하는 방법
type Add = {(a:number, b:number) : number}

 

overloading

overloading 함수가 서로 다른 여러개의 call signatures를 가지고 있을 때 발생한다.

type Add = {
    (a: number, b: number) : number
    (a: number, b: string) : number
}

const add: Add = (a, b) => {
    if(typeof b === 'string') return a
    return a + b
}

 

// 다른 여러개의 argument를 가지고 있을 때 발생하는 효과
type Add = {
    (a: number, b: number): number;
    (a: number, b: number, c: number): number;
}

const add:Add = (a, b, c) => {
    return a+b
} // error 다른 개수의 파라미터를 가지면 나머지 파라미터도 타입을 지정해야함

const add:Add = (a, b, c?: number) => {
    return a+b
}

 

극복!

const add: Add = (a, b, c?: number) => {
    if (typeof c !== 'undefined') {
        return a + b + c
    }
    return a + b
} // 통과

const add: Add = (a, b, c?: number) => {
    if(c) return a + b + c
    return a+b
}

 

 

generics

C#이나 Java와 같은 언어에서 재사용 가능한 컴포넌트를 만들기 위해 사용하는 기법이다.

타입스크립트에서는 인터페이스, 함수 등의 재사용성을 높일 수 있다.

선언이 아닌 생성때 타입을 명시하여 다양하게 사용하며 한번만 선언해서 재사용성이 매우 높다.

쓰지 않을 경우, 불필요한 타입 변환을 하기 때문에 프로그램의 성능에 악영향을 끼친다. (?)

type SuperPrint = { 
    // call signature 3개
    (arr: number[]):void
    (arr: boolean[]):void
    (arr: string[]):void
}

const superPrint: SuperPrint = (arr) => {
    arr.forEach(i => console.log(i))
}

superPrint([1, 2, 3, 4])
superPrint([true, false])
superPrint(["1", "2"])
superPrint(["1","2",3,false]) // error

 

call signature을 작성할 때, 들어올 확실한 타입을 모를 때 generic 사용한다.

type SuperPrint = { 
    // generic 선언(지칭은 상관 없음)
    <Generic>(arr: Generic[]):void
}

const superPrint: SuperPrint = (arr) => {
    arr.forEach(i => console.log(i))
}

// 값을 보고 유추하고 발견한 타입으로 변경
superPrint([1, 2, 3, 4])
superPrint([true, false])
superPrint(["1", "2"])
superPrint(["1","2",3,false])
// 1 
type SuperPrint = { 
	 // return하는 값이 있어서 void에서 변경
    <Generic>(arr: Generic[]):Generic
}

const superPrint: SuperPrint = (arr) => arr[0]

const a = superPrint([1, 2, 3, 4])

console.log(a) // 1
// 2
function superPrint<G>(a: G[]) {
    return a[0]
}

console.log(superPrint([1, 2, 3, 4])) // 1

 

generic 2번 사용법

type SuperPrint = { 
    // generic을 처음 인식했을 때의 순서를 기반으로 타입을 추론
    <G1,G2>(arr: G1[], b:G2):G1
}

 

generic 기본 응용 사용법

type Player<G> = {
    name: string,
    info: G 
}

// 1
const kai: Player<{food:string}> = {
    name: "kai",
    info: {
        food:"milk"
    }
}

// 2
type kaiPlayer = Player<{food:string}>

const kai: kaiPlayer = {
    name: "kai",
    info: {
        food:"milk"
    }
}

// 3
type KaiInfo = {
    food: string
}
type kaiPlayer = Player<KaiInfo>

const kai: kaiPlayer = {
    name: "kai",
    info: {
        food: "milk"
    }
}

 

 

 

 

 

 

참고링크

 

TypeScript | Generic 제네릭 (feat. TypeScript 두 달차 후기)

타입스크립트 제네릭의 여러 사용 방법에 대해 정리해봅니다.

velog.io

 

728x90