Tech

Diary

Lecture

개발중

About Me

개발중

공변성, 반공변성

JeongSeulho

2024년 07월 29일

준비중...
클립보드로 복사
thumbnail

1. 공변성과 반공변성

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

타입스크립트는 기본적으로 공변성을 따르지만 strictFunctionTypes 옵션이 true인 경우 함수의 파라미터는 반공변성을 따른다.(strict mode가 아닌 경우 이변성을 따름)

2. 공변성

copy
// 조건부 타입 : T가 P에 속해있으면 ? true : false
type IsSubtypeOf<T, P> = T extends P ? true : false;

// string은 string | number의 서브타입이다.
type T0 = IsSubtypeOf<string, string | number>; // true

// Array<string>은 Array<string | number>의 서브타입이다.
type T1 = IsSubtypeOf<Array<string>, Array<string | number>>; // true
// Array<string | number>은 Array<string>의 서브타입이 아니다.
type T2 = IsSubtypeOf<Array<string | number>, Array<string>>; // false

// { a: string; b: number }은 { a: string | number; b: number }의 서브타입이다.
type T3= IsSubtypeOf<{ a: string; b: number }, { a: string | number; b: number }>; // true
// { a: string | number; b: number }은 { a: string; b: number }의 서브타입이 아니다.
type T4 = IsSubtypeOf<{ a: string | number; b: number }, { a: string; b: number }>; // false

3. 반공변성

함수의 파라미터에서는 반공변성을 따른다, 아래 예에서 (x: string | number) => number(x: string) => number의 서브타입이다.

copy
function a(x: string): number {
  return 0;
}

type B = (x: string | number) => number;

let b: B = a; // ERROR - string | number' 형식은 'string' 형식에 할당할 수 없습니다,  'number' 형식은 'string' 형식에 할당할 수 없습니다.
copy
function a(x: string | number): number {
  return 0;
}

type B = (x: string) => number;

let b: B = a;

4. 공변성과 반공변성의 시스템 이해하기

공변성의 경우 직관적으로 이해할 수 있지만 반공변성은 직관적이지도 않으며, 왜 저렇게 동작하도록 했는지 궁금하여 정리한다.
타입을 설정하는 근본적인 이유는 안전하게 사용하기 위함이다. 공변성과 반공변성은 모두 타입 안전성을 보장하기 위한 것이다.

4.1 일반 변수 할당과 리턴 타입에 대한 공변성

copy
type FN2 = (x: string) => string | number;
const fn2: FN2 = (x: string) => 'string';

type SN = string | number;
let sn: SN = 'string';

이러한 변수와 리턴의 타입을 정했다는 것은 내가 사용할 값의 범위를 정했다는 것이다, 당연히 내가 사용할 값의 범위(타입)내에 실제 구현체가 있어야 한다.

4.2 함수 파라미터 타입에 대한 반공변성

copy
type FN1 = (x: string | number) => null;
const fn1: FN1 = (x: string) => null; // ERROR 

함수 파라미터에 대한 반공변성은 함수가 사용할 값의 범위를 정했다는 것이다, 내가 아닌 함수가 사용할 값이기 때문에 함수가 사용할 값의 범위(실제 구현체)내에 타입이 있어야 한다.
위의 예에서 fn1string만을 처리할 수 있는 함수인데, 타입으로는 number도 처리가능하다고 정의했기 때문에 에러가 발생한다.
즉 값의 사용 주체가 인지 함수인지에 따라 공변성과 반공변성이 달라진다, 사용 주체가 함수라면 해당 함수의 구현체를 기준으로 그 보다 좁은 범위의 파라미터 타입을 주어야 안전하게 사용할 수 있다.

출처
inpa님의 tistoryundefcat님의 velog