함수 타입 표현식과 호출 시그니쳐
- 호출 시그니쳐는 함수 매개변수와 타입을 정의하는 부분을 따로 떼어 정의해놓은걸 갖다 쓰는 모습을 호출 시그니쳐라고 부른다.
type Operation2 = {
(a: number, b: number) : number
}
const add2: Operation2 = (a, b) => a + b;
- 여기 add2에 정의된 Operation2처럼 { } 중괄호 안에 정의하거나,
type Add = (a: number, b: number) => number;
const add: Add = (a, b) => a + b;
- add 처럼 중괄호 안하고 화살표로 정의할 수 있다.
- 개인적으로 화살표로 하는 게 더 보기 편한듯하다.
함수 타입의 호환성
- 함수는 매개변수의 타입과 반환값의 타입을 정해줄 수 있는데, 반환값은 기존 타입처럼 업캐스팅이 가능하지만, 다운캐스팅은 안된다.
- 하지만
매개변수를 비교할 때 기존에 타입으로 봤었던 다운캐스팅, 업캐스팅과는 반대로 다운캐스팅이 되고, 업캐스팅은 되지 않는다.
함수 오버로딩
- 하나의 함수를 매개변수의 개수나 타입에 따라 여러가지 버전으로 만드는 문법이다.
- 많은 라이브러리들을 보면 이런식으로 되어있으니 알아두면 좋다.
function func(a: number): void;
function func(a: number, b: number, c: number): void;
function func(a: number, b?: number, c?: number) {
if (typeof b === "number" && typeof c === "number") {
console.log(a + b + c);
} else {
console.log(a * 20);
}
}
- 오버로드 시그니쳐를 이용해 하나의 함수에 여러 버전들을 만들어놓는다.
- 실제 구현 - 구현 시그니쳐에서 매개변수에 모든 버전을 수용하기 위해 ?를 활용하고, 타입가드를 통해 원하는 동작이 되도록 하였다.
사용자 정의 타입 가드
- 개와 고양이 타입이 있다고 하자. 사실 서로소 유니온 타입으로 지정하면 타입가드를 할 수 있으나, 어디 라이브러리라던가 내가 함부로 못바꾸는 타입 정의라고 가정하자.
type Dog = {
name: string;
isBark : boolean
}
type Cat = {
name: string;
isScratch : boolean
}
type Animal = Dog | Cat
function warning(animal : Animal){
if("isBark" in animal){
}else if("isScratch" in animal){
}
}
- 간단하게는 warning 함수를 위와같이 정의할 수 있다. 그치만,, 보기 별로고 직관적이지 않고 만약 isBark 이런거 바뀌면 또 어떻게 수정하나.. 매우 번거로운 일이 될 수 있다.
- 그걸 해결하기 위해, 개인지 고양이인지를 알려주는 함수를 만들어 그 함수를 타입 가드로 대신하는 작업이다.
function isDog(animal: Animal){
return animal.isBark !== undefined
}
- 이렇게 하면 될거 같은데 빨간줄이 발생한다. animal이 dog인지 cat인지 모르는 상황이기 때문이다.
- 그럴땐 return animal에 소괄호를 치고 타입 정의를 해주면 된다 !
function isDog(animal: Animal) {
return (animal as Dog).isBark !== undefined;
}
- 이렇게 타입 정의를 해주면 모든 문제 해결 ~~~ 인줄 알았지만 아니다.
- 여전히 warning 함수에서는 타입이 제대로 좁혀지지 않았다.

function warning(animal: Animal) {
if (isDog(animal)) {
animal.isBark
} else if ("isScratch" in animal) {
animal
}
}
- 분명 좁혔는데 왜 안될까? 이럴때 추가로 isDog 함수의 반환되는 값의 타입을 정확히 또 지정해주는 것이다.
function isDog(animal: Animal): animal is Dog {
return (animal as Dog).isBark !== undefined;
}
animal is Dog
는 return문이 참일 때, 아 ~ animal은 Dog구나! 라고 알려주는 것이다.
- 이렇게까지 하면, warning에서 타입가드를 제대로 좁힐 수 있게 된다.

- 에러 없는 모습.
- isCat도 동일하게 작성하면 된다.
function isCat(animal: Animal) : animal is Cat{
return (animal as Cat).isScratch !== undefined
}
function isCat(animal: Animal) : animal is Cat{
return (animal as Cat).isScratch !== undefined
}
function isDog(animal: Animal): animal is Dog {
return (animal as Dog).isBark !== undefined;
}
function warning(animal: Animal) {
if (isDog(animal)) {
animal.isBark
} else if (isCat(animal)) {
animal.isScratch
}
}
마치며
- 지난 글인 서로소 유니온 타입에서 명확한 타입 좁히기를 통해 더 알아보기 쉬운 타입으로 이해할 수 있었듯, 함수 타입 좁히기도 타입 정의만 잘 해준다면 더 이해하기 쉬운 타입 코드가 될 수 있다는 것을 알았다.