함수의 arguments와 return type을 알려주는 것을 Call Signatures라고 한다.

function add(a:number, b:number) {
return a + b;
}
이렇게 만들면 a, b는 number임은 물로 return값도 number이라는 것을 안다.
다른 방식으로 선언해보자
const add = (a:number, b:number) => a + b
만약 a와 b에 타입을 작성하지 않는 다면?
add 함수만의 타입을 만들고 싶다면?
type Add = (a:number, b:number) => number;
const add:Add = (a, b) => a + b;
이는 내가 type을 만들수 있고 함수의 arguments와 return type을 작성할 수 있다.
react.js를 사용하면 props로 함수를 보내게 된다면 타입스크립트에게 설명해줘야 한다.
프로그램을 디자인하면서 타입을 먼저 생각하고 그 다음 코드를 구현하게 된다.
실제로 오버로딩된 함수를 직접 작성하는 경우는 많이 없다.
대부분 다른 사람이 만든 외부 라이브러리를 사요하는데 이런 패키지나 라이브러들은 오버로딩을 많이 사용한다.
오버로딩은 함수가 여러개의 call signatures를 가지고 있을때 발생
type Add = {
(a: number, b: number) : number
(a: number, b: string) : number
}
만약 이렇게 작성한다면 Typescript는 a는 항상 number b는 number | string으로 인식한다.
그래서 이럴 경우 어떤 type인지 확인해야 한다.
const add: Add = (a, b) => {
if(typeof b === "string") return a;
return a + b;
}
물론 이건 매우매우매우매우매우매우 바보같은 예시이긴하다.
하지만 오버로딩의 핵심을 보여준다.
오버로딩은 여러 call signatures가 있는 함수이다.
우리가 사용하는 next.js를 들어보자 페이지 이동할때 아래와 같이 사용할 수 있다.
Router.push({
path:"/home",
state: 1
})
Router.push("/home")
이렇게 String으로도 Object로도 보낼 수 있다.
type Config = {
path: string,
state: object
}
type Push = {
(path: string) : void
(config: Config): void
}
const push:Push = (config) => {
if(typeof config === "string")
console.log(config);
else {
console.log(config.path);
console.clog(config.state)
}
}
이런 것을 오버로딩이라고 하고 라이브러리에서 정말 많이 사용된다.
만약에 argument가 여러개면 어떻게 될까?
type Add = {
(a:number, b:number) : number
(a: number, b: number, c:number): number
}
const add:Add = (a, b, c?:number) => {
if(c) return a + b+ c
return a + b;
}
이렇게 타입스크립트 매개변수의 경우가 다를 경우
add function에 c가 들어올수도 아닐수도 있는 c:number 부분은 필수가 아니라 옵션이라고 생각한다.
추가 파라미터 옵션이라고 판단하기 때문에 타입을 지정해줘야한다.
이건 자주 보는 경우는 아니다.
type SuperPrint = {
(arr: number[]):void
}
const superPrint : SuperPrint = (arr) => {
arr.forEach(i => console.log(i))
}
이렇게 작성할 경우 숫자 배열만을 처리할 수 있다.
다른 데이터타입을 처리해야할 경우는 어떻게 해야할까
type SuperPrint = {
(arr: number[]):void
(arr: boolean[]):void
}
이러면 boolean array도 처리가 가능하다.
만약 string을 추가 하고 싶다면 저 아래에 또 추가해야할까?
이렇게 하면 우린 모든 가능성을 다 예상해서 만들어야 한다.
이럴때는 generic을 사용한다.
type SuperPrint = {
<T>(arr : T[]) : void
}
const superPrint : SuperPrint = (arr) => {
arr.forEach(i => console.log(i))
}
superPrint([1,2,3,4])
superPrint([true, false, true])
superPrint(["a", "b", "c"])
superPrint([1, 2, true, false])
이렇게 Generic을 사용하면 모든 것이 해결된다.
type SuperPrint = {
<T> (arr: T[]) T
}
우리가 한것은 Typescript에게 타입을 유추하도록 알려줬다.
그리고 그 타입의 배열이 될 것이라는 것을 인지하고 그 타입 중 하나를 리턴하도록 설명해준 것이다.
