
타입스크립트는 생각보다 복잡했다...
하지만 계속 가보자고!
호출 시그니처는 타입스크립트에서 함수의 타입을 지정할 때 사용하는 문법이다. 함수에 함수를 인수로 전달하거나, 함수를 반환하는 경우 이 문법을 통해 인수나 반환 함수의 타입을 지정할 수 있다.
예시)
type Add = (a: number, b: number) => number
const add: Add = (a, b) => a + b
다음과 같은 스크립트가 있다고 치자. 그렇다면 여기서 마우스를 add 위로 가져오게되면 VS code 상에서 add 라는 함수에 들어올 인자들의 타입이 뜨게 될텐데 이부분이 호출 시그니처이다. 간단히 여기서는 위에 type 부분이라고 보면 될것이다.
동일한 이름에 매개 변수만 다른 여러 버전의 함수를 만드는 것을 함수의 오버로딩이라고 한다. 파라미터의 형태가 다양한 여러 케이스에 대응하는 같은 이름을 가진 함수를 만드는 것이라고 볼 수 있다.
실제로 사용할 일은 적은편이며 보통 라이브러리에서 오버로딩을 많이 사용한다고 한다. 그래도 일단 개념정도는 숙지하고 가보자.
예시)
Next.js 에서 라우팅하는 방법의 예시이다.
1번) Router.push({
path: "/home",
state: 1
})
2번) Router.push("/home")
다음과 같이 object로 보낼수도, string 으로 보낼수도 있는데(일단 2번이 편해보이고 실제로도 2번밖에 안써봤지만) 오버로딩을 사용해 이렇게 경우에 따라 다르게 실행 할 수 있다.
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) } }
또 다른 예시로는 인자가 2개가 들어갈 수도 3개가 들어갈 수도 있는 경우
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 함수에서 c인자만 타입을 지정해준 이유는 뭘까 하고 생각했는데 내가 이해한것으로는 콜시그니쳐의 인자의 갯수가 다를 경우 옵셔널로 오는 인자는 타입 지정을 해줘야 한다고 한다.
다양한 모양(shape)이 있는 함수라고 한다. 여기서는 모양 보다는 형태라고 하는게 맞겠다. Generics 를 통해 실현 할 수 있다. 타입스크립트에는 콘크리트 타입이라 불리는 number, string, boolean 등의 타입들이 있는데 다음으로 올 타입이 어떤 타입인지 모를때 Generics 를 사용할 수 있다. 사용 방법은 다음과 같으며 일반적으로 T라는 문자를 사용한다.
type SuperPrint = {
<T>(arr: T[]): T }
const superPrint : SuperPrint = (arr) => arr[0]
제네릭을 하나 더 쓰고 싶다면? 이렇게 쓰면 된다
type SuperPrint =
<T, M>(a: T[], b: M) => T
그렇다면 이런 의문이 들 수 있다. 어떤 타입이 올지 모를때 사용한다면 any 와 다를바가 없는게 아닌가?
타입스크립트의 공식 문서를 확인해보자

대략적인 해석은 다음과 같다.
" 제네릭 타입이 없다면 특정 타입을 지정해줘야 하거나 any 를 사용 할 수도 있다. any 타입은 확실히 제네릭(포괄적)이긴 하지만 함수 반환시에 타입에 대한 정보를 잃게 된다. 그러므로 반환 타입을 명시해주기 위해서 제네릭타입을 사용한다."
해석하다보면 generic이라는 단어 때문에 헷갈릴수 있는데 결국 any는 반환의 타입을 특정할 수 없는 반면 generic타입을 사용하면 반환 타입을 특정할 수 있다는 얘기 같다. 아무튼 어떤게 올지 모를때는 generic을 사용하는것으로!