Typescript
공변성과 반공변성을 알아야 함수끼리 대입 할 수 있다
비숑주인
2025. 3. 29. 20:42
TypeScript에서는 함수 타입끼리도 대입이 가능하지만, 어떤 경우는 되고 어떤 경우는 안 된다. 그 차이를 이해하기 위해서는 공변성(covariance), 반공변성(contravariance)이라는 개념이 필요하다.
변성(Variance)이란?
개념 | 설명 |
공변성 | A → B일 때, T<A> → T<B> 가능 |
반공변성 | A → B일 때, T<B> → T<A> 가능 |
이변성 | 양방향 대입 모두 가능 |
무공변성 | 둘 다 불가능 |
TypeScript는 기본적으로 반환값에는 공변성, 매개변수에는 반공변성을 적용한다. 단, strictFunctionTypes 옵션이 꺼져 있으면 매개변수는 이변성으로 작동한다.
함수의 반환값은 공변성
function a(x: string): number {
return 0;
}
type B = (x: string) => number | string;
let b: B = a; // ✅ OK
- number → number | string 으로 대입 가능
- 이유: 반환값은 공변성이 적용되기 때문에 더 좁은 타입을 더 넓은 타입에 대입 가능
반대로 하면?
function a(x: string): number | string {
return 0;
}
type B = (x: string) => number;
let b: B = a; // ❌ 에러
string | number는 number에 대입할 수 없기 때문에 에러가 난다.
함수의 매개변수는 반공변성 (strict 모드일 때)
function a(x: string | number): number {
return 0;
}
type B = (x: string) => number;
let b: B = a; // ✅ OK
- string → string | number는 OK
- 이유: 매개변수는 반공변성, 즉 더 넓은 인자를 받는 함수는 더 좁은 타입에 대입 가능
반대로 하면?
function a(x: string): number {
return 0;
}
type B = (x: string | number) => number;
let b: B = a; // ❌ 에러 (strict 모드에서)
- string | number를 기대하는 곳에 string만 받는 함수는 안전하지 않음
하지만 strictFunctionTypes를 꺼두면
// strict 모드 해제 시
let b: B = a; // ✅ OK (이변성 적용)
strictFunctionTypes의 영향
매개변수 변성 | strictFunctionTypes = true | strictFunctionTypes = false |
매개변수 | 반공변성 (안전) | 이변성 (느슨함) |
반환값 | 항상 공변성 | 항상 공변성 |
메서드에서 변성이 달라지는 이유
const sayFunc = (a: string): string => 'hello';
1. 인터페이스에서 메서드 방식 선언 → 이변성
interface SayMethod {
say(a: string | number): string;
}
const obj: SayMethod = {
say: sayFunc // ✅ 허용됨 (매개변수 이변성)
};
2. 함수 타입 방식 선언 → 반공변성
interface SayFunction {
say: (a: string | number) => string;
}
const obj: SayFunction = {
say: sayFunc // ❌ 에러 (매개변수 반공변성)
};
이유는 TypeScript 내부 구현 방식에서 메서드 선언은 매개변수를 이변성으로 처리하고, 함수 타입 선언은 매개변수를 반공변성으로 처리하기 때문이다
언제 기억해야 할까?
- 함수 반환값은 항상 공변성 → 좁은 타입을 넓은 타입으로 대입 가능
- 함수 매개변수는 strict 모드에서 반공변성, 아니면 이변성
- strictFunctionTypes 설정 여부가 함수 대입 가능성에 직접적 영향
- 메서드는 이변성, 함수 타입은 반공변성으로 동작
함수끼리 타입 대입을 정확하게 이해하려면 공변성 vs 반공변성 개념이 필수적이다.
특히 매개변수 쪽은 방향이 반대라는 점, 그리고 strict 모드 여부에 따라 동작이 달라진다는 점을 기억하자.