📑 목차
타입스크립트에서 함수 타입의 호환성이란, 특정 함수 타입을 다른 함수 타입으로 취급해도 괜찮은지(할당 가능한지)를 판단하는 것을 말한다.
함수 타입의 호환성은 다음 2가지 기준으로 체크한다.
- 반환값(Return) 의 타입이 호환되는가?
- 매개변수(Parameter) 의 타입이 호환되는가?
하나씩 자세히 살펴보자.
1. 기준 1: 반환값 타입이 호환되는가?
반환값은 우리가 아는 일반적인 객체 타입의 호환성 원칙(공변성)과 같다. 즉, A의 반환값이 B의 반환값의 서브 타입(자식)이어야 호환된다. (업캐스팅 가능)
type A = () => number;
type B = () => 10;
let a: A = () => 10;
let b: B = () => 10;
a = b; // ✅ OK (number는 10을 포함함)
// b = a; // ❌ NO (10은 number 전체를 포함하지 못함)
변수 a는 number를 반환하기를 기대하고, b 함수는 10을 반환한다. 10은 number에 속하므로 호환된다. 반대는 성립하지 않는다.
2. 기준 2: 매개변수의 타입이 호환되는가?
매개변수의 호환성은 매개변수의 개수가 같은지 다른지에 따라 판단 기준이 달라진다.
2-1. 매개변수의 개수가 같을 때 (반공변성)
이 부분이 가장 헷갈리는 부분이다. 결론부터 말하면 반환값과는 반대로, 할당하려는 함수의 매개변수 타입이 더 상위(슈퍼) 타입이어야 호환된다.
일반적인 객체 호환성과 반대되는 개념이라 반공변성(Contravariance) 이라고도 부른다.
type C = (value: number) => void;
type D = (value: 10) => void;
let c: C = (value) => {};
let d: D = (value) => {};
// c = d; // ❌ NO (number <-- 10 : 업캐스팅 같지만 함수 매개변수에서는 안 됨)
d = c; // ✅ OK (10 --> number : 다운캐스팅 같지만 함수 매개변수에서는 됨)
왜 반대일까? (객체 예시로 이해하기)
Animal(부모)과 Dog(자식) 타입을 예로 들어보자.
type Animal = { name: string };
type Dog = { name: string; color: string };
let animalFunc = (animal: Animal) => {
console.log(animal.name);
};
let dogFunc = (dog: Dog) => {
console.log(dog.name);
console.log(dog.color);
};
// animalFunc = dogFunc; // ❌ 불가능
dogFunc = animalFunc; // ✅ 가능
- 불가능한 이유 (
animalFunc = dogFunc):animalFunc는Animal타입의 인수를 받는다. 만약 여기에dogFunc를 할당해버리면,dogFunc는 내부적으로dog.color를 찾으려 할 것이다. 하지만Animal타입에는color가 없으므로 런타임 에러가 발생할 수 있다. - 가능한 이유 (
dogFunc = animalFunc):dogFunc는Dog타입의 인수를 받는다. 여기에animalFunc를 할당하면,animalFunc는 들어온 인수에서name만 사용한다.Dog타입에는name이 보장되어 있으므로 안전하다.
결론: 매개변수 개수가 같을 때는 매개변수 타입이 더 넓은(슈퍼 타입인) 함수를 대입해야 안전하다.
2-2. 매개변수의 개수가 다를 때
매개변수의 개수가 다를 때는 비교적 단순하다. 매개변수의 개수가 더 적은 함수는 호환된다. (단, 타입은 같아야 함)
type Func1 = (a: number, b: number) => void;
type Func2 = (a: number) => void;
let func1: Func1 = (a, b) => {};
let func2: Func2 = (a) => {};
func1 = func2; // ✅ OK (인자 2개 받는 자리에 1개 받는 함수 넣기 가능)
// func2 = func1; // ❌ NO (인자 1개 받는 자리에 2개 필요한 함수 넣기 불가)
자바스크립트/타입스크립트에서는 함수에 정의된 매개변수보다 더 많은 인자를 넘겨도, 함수가 알아서 무시하고 실행되기 때문에 이는 안전한 동작으로 간주된다.
요약
- 반환값: 일반적인 객체와 똑같다. (자식 타입을 부모 타입에 할당 가능 - 업캐스팅)
- 매개변수 (개수 같음): 일반적인 객체와 반대다. (부모 타입을 자식 타입에 할당 가능 - 반공변성)
- 매개변수 (개수 다름): 매개변수가 더 적은 쪽을 할당할 수 있다.
