함수 타입의 호환성이란?
함수 타입의 호환성이란 특정 함수 타입을 다른 함수 타입으로 취급해도 괜찮은지 판단하는 것을 의미한다.
함수 타입 호환성의 판단 기준
기준 1: 반환값 타입이 호환되는가?
type A = () => number;
type B = () => 10;
let a: A = () => 10;
let b: B = () => 10;
a = b; // ✅
b = a; // ❌
A의 반환값 타입은 Number, B의 반환값 타입은 Number Literal이다. 변수 a에 b를 할당할 수 있지만, b에 a를 할당할 수는 없다.
반환값 타입은 일반적인 타입 호환성 규칙을 따른다. 슈퍼타입에 서브타입을 할당할 수 있다.
기준 2: 매개변수의 타입이 호환되는가?
2-1. 매개변수의 개수가 같을 때
type C = (value: number) => void;
type D = (value: number) => void;
let c: C = (value) => {};
let d: D = (value) => {};
c = d; // ✅
d = c; // ✅
위와 같이 매개변수 타입이 완전히 동일하면 서로 호환된다.
type C = (value: number) => void;
type D = (value: 10) => void;
let c: C = (value) => {};
let d: D = (value) => {};
c = d; // ❌
d = c; // ✅
이 코드에서는 C의 매개변수 타입이 Number, D의 매개변수 타입이 Number Literal이다.
따라서, C 매개변수의 타입이 D 매개변수의 슈퍼타입이므로 D를 C로 취급할 수 없지만, C를 D로 취급할 수는 있다.

매개변수 타입의 경우 반환값과 반대로 작동한다. 업캐스팅은 불가능하고 다운캐스팅만 가능하다.
이러한 규칙이 이해하기 어렵다면 객체 타입을 예로 들어보자.
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를 할당할 수 없지만, dogFunc에 animalFunc를 할당할 수는 있다. dogFunc의 매개변수 타입이 animalFunc의 매개변수 타입보다 작은 서브타입이기 때문이다.
Animal은 Dog의 슈퍼타입이지만, 함수 매개변수에서는 서브타입을 슈퍼타입에 할당할 수 없다.

다음의 코드를 보자
let textFunc = (animal: Animal) => {
console.log(animal.name);
console.log(animal.color); // ❌
};
textFunc 타입의 매개변수 타입은 Animal이다.
함수 내부에서는 name 프로퍼티뿐 아니라 Dog 타입에만 존재하는 color 프로퍼티에도 접근한다. 만약 animalFunc = dogFunc를 허용하면, Animal 타입의 인수가 전달되었을 때 존재하지 않는 color 프로퍼티에 접근하게 되므로 오류가 발생한다.

let textFunc2 = (dog: Dog) => {
console.log(dog.name)
};
반면, textFunc2의 매개변수 타입은 Dog이다. 함수 내부에서는 Dog 타입에도 존재하는 name 프로퍼티에만 접근한다. Dog 타입의 인수가 전달되어도 함수는 name 프로퍼티만 사용하므로 dogFunc = animalFunc는 안전하다.
즉, 매개변수 타입은 반환값과 반대로 작동한다. 슈퍼타입을 서브타입에 할당할 수 있다.
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; // ✅
func2 = func1; // ❌
func1 = func2는 호환된다. func2는 a만 받으므로, func1처럼 a, b 두 개를 받는 타입보다 요구사항이 적기 때문이다.
func2 = func1은 호환되지 않는다. func2 타입은 매개변수 1개만 받지만, func1은 2개를 요구하므로 호환되지 않는다.
'TIL' 카테고리의 다른 글
| [TS] 함수 오버로딩 (0) | 2025.11.01 |
|---|---|
| [TS] 함수 타입 정의 및 호출 시그니처 연습 (0) | 2025.11.01 |
| [TS] 함수 타입 표현식과 호출 시그니처 (0) | 2025.11.01 |
| [TS] 함수의 타입 정의 (0) | 2025.11.01 |
| [TS] 타입 단언 및 서로소 유니온 사용 연습 (0) | 2025.11.01 |
