[Typescript] 공변성과 반공변성

Bewell·2024년 3월 16일
post-thumbnail

최근 업데이트 24.03.16

  • 타입스크립트에서 타입 간에 서로 대입할 때 대입되는 경우와 대입이 되지 않는 경우를 파악하기 위해 알아야한다
  • 공변성과 반공변성을 아는 것은 타입과 서브타이핑을 이해하는데 도움이 된다
💡 서브타이핑
서브타이핑은 다형성의 한 형태로, '서브 타입'이 '베이스 타입'과
어떤 형태의 '대체 가능성'에 의해 연결되는 것인지 의미한다
'대체 가능성'은 '베이스 타입'의 변수가 '서브 타입' 값도 받아 들일 수 있음을 의미
  • 공변성과 반공변성의 이론은 매우 복잡하고 어려워서 결론적인 내용만 설명한다


가장 핵심은

✅ 리턴값은 넓은 타입으로 대입되고, 반대로 매개변수는 좁은 타입으로 대입된다.

공변성(Covariance) : A가 B의 서브타입이면, T<A>T<B>의 서브타입이다.
반공변성(Contravariance) : A가 B의 서브타입이면, T<B>T<A>의 서브타입이다.



공변성

let stringArray: Array<string> = [];
let array: Array<string | number> = [];

array = stringArray; // OK - stringArray는 array를 포함
stringArray = array; // Error

// --------------------------------------------------

let subObj: { a: string; b: number } = { a: '1', b: 1 };
let superObj: { a: string | number; b: number } = subObj; // superObj는 subObj 포함

// subObj <: superObj
// 각각의 프로퍼티가 대응하는 프로퍼티와 같거나 서브타입이어야 한다.
  • 우선 기본적으로 생 string 은 유니온 string | number 의 서브 타입이다.
  • 그래서, Array 은 Array<string | number> 의 서브 타입이 된다
  • 그리고 { a: string; b: number } 도 { a: string | number; b: number } 의 서브 타입이 된다. 
  • 이렇게 A가 B의 서브타입일 때, T<A> 가 T<B> 의 서브타입이 된다면, T를 공변적이라고 부를 수 있다.


function a (x:string) {
    return +x
}

a('1')    //  1

type B = (x: string) => number | string
const b: B = a





반공변성

type Logger<T> = (param: T) => void;

let logNumber: Logger<number> = (param) => {
   console.log(param); // number
 };

let log: Logger<string | number> = (param) => {
  console.log(param); // string | number
};

logNumber = log; // OK
log = logNumber; // Error

// 기본적으로 number <: string | number 지만, 함수 매개변수 제네릭에서는 거꾸로
// Logger<string | number> <: Logger<number>
  • 위의 코드를 보면 인자로 string | number 를 받는 log 함수와, 인자로 number 만을 받는 logNumber 함수가 있다.

  • 원래라면, 공변성의 규칙에 따르면, log 함수는 넓은 타입이고, logNumber는 좁은 타입이니, log = logNumber 식은 성립되야 하지만 에러가 발생한다.

  • 함수의 매개변수의 타입을 다룰경우 반공변성으로 따르기 때문이다.

  • 따라서 logNumber = log 가 성립 된다.



function a (x: string | number) {
    return +x
}

type B = (x: string) => number
let b: B = a


정리하면

  • 함수의 리턴 타입

    • 리턴 타입이 좁은 타입넓은 타입에 넣기
  • 함수의 파라미터 타입

    • 파라미터 타입이 넓은 타입좁은 타입에 넣기
  • 타입스크립트는 기본적으로 공변적으로 동작하나, 타입스크립트의 파라미터는 반공변적으로 동작한다






참고자료_1
참고자료_2

0개의 댓글