TS - 공변성과 반공변성

정윤호·2024년 7월 3일
1

코드잇잇잇!

목록 보기
26/30

서론

타입스크립트에서 악명이 높은 공변성과 반공변성에 대해 알아보자.
먼저, 이 포스트는 tsconfig의 strictFunctionTypes 옵션이 true 인 경우를 기준으로 말함을 알린다.

{
	"compilerOptions": {
		"strictFunctionTypes": true;
	}
}

공변성 (Covariance): 좁은 타입을 넓은 타입에 대입 O / 넓은 타입을 좁은 타입에 대입 X

공변성은 한 타입이 다른 타입의 서브타입(subtype)일 때, 그 타입을 사용하는 다른 모든 맥락에서도 서브타입 관계가 유지되는 성질을 말한다.

예를 들어, 배열 타입은 공변적인데, AnimalDog의 슈퍼타입이라면, Animal[]Dog[]의 슈퍼타입이다.

interface Animal {
  name: string;
}

interface Dog extends Animal {
  breed: string;
}

let animals: Animal[] = [{ name: '여름이' }];
let dogs: Dog[] = [{ name: '여름이', breed: '말티즈' }];

animals = dogs; // 정상: Dog[]는 Animal[]의 서브타입
dogs = animals; // 에러: 넓은 타입을 좁은 타입에 대입 X

|300|300

즉, Dog ⊂ Animal 이므로, Dog[] ⊂ Animal[] 의 관계 또한 성립하는 것을 공변성이라고 한다.

함수의 반환값의 타입 역시 공변적이다.

type giveDog = (a: string) => Dog;
declare const giveMaltese: (a: string) => Maltese;
declare const giveAnimal: (a: string) => Animal;

const dog: giveDog = giveMaltese; // 정상: Maltese ⊂ Dog 이므로 giveMaltese ⊂ giveDog
const dog: giveDog = giveAnimal; // 넓은 타입을 좁은 타입에 대입 X

|300

반공변성 (Contravariance): 넓은 타입을 좁은 타입에 대입 O / 좁은 타입을 넓은 타입에 대입 X

반공변성은 한 타입이 다른 타입의 서브타입일 때, 그 타입을 매개변수로 사용하는 모든 맥락에서 역으로 서브타입 관계가 유지되는 성질을 말한다.

예를 들어, 함수 매개변수 타입은 반공변적이다.

type takeDog = (a: Dog) => string;
declare const takeMaltese: (a: Maltese) => string;
declare const takeAnimal: (a: Animal) => string;

const dog: takeDog = takeMaltese; // 에러: 함수의 매개변수는 반공변성을 따라 좁은 타입을 넓은 타입에 대입 X
const dog: takeDog = takeAnimal; // 정상: Dog ⊂ Animal 이지만 takeAnimal ⊂ takeDog

|300

  • 첫 번째 대입에서 에러가 발생하는 이유는 takeMaltese 함수는 Maltese 타입만 받아들일 수 있는데, takeDog 타입은 더 넓은 범위인 Dog 타입을 받아들일 수 있어야 하기 때문이다. 만약 takeDog 타입이 takeMaltese 타입을 받아들이면, Dog 타입의 다른 서브타입을 전달할 때 문제가 발생할 수 있다. 따라서 이는 타입 안전성을 보장하지 못한다.
  • 두 번째 대입은 정상이다. takeAnimal 함수는 Animal 타입을 받아들이기 때문에 Dog 타입도 받아들일 수 있다. 즉, takeAnimal은 더 넓은 범위를 받아들이기 때문에 takeDog 타입으로 대입이 가능하다. 이는 타입 안전성을 유지한다.

반공변성은 타입 시스템에서 매개변수의 타입을 설정할 때 매우 중요하다. 함수의 매개변수 타입이 서브타입으로 대체될 경우, 호출 시점에 잘못된 타입이 전달될 수 있다. 예를 들어, takeDog 타입이 takeMaltese 타입으로 대체되면, Dog 타입의 다른 서브타입 (예: Bulldog)이 전달될 때 문제가 발생할 수 있다. 반대로, 더 넓은 타입인 Animal 타입을 사용하는 것은 안전하다.

출처

제로초 유튜브

profile
우리 인생 화이팅~

0개의 댓글