일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- async/await
- useAppDispatch
- TS
- webpack
- tailwind
- CORS
- RTK Query
- 리터럴 타입
- 투포인터
- app router
- Jest
- 태그된 유니온
- 인터섹션
- 공변성
- 타입 좁히기
- 이분 검색
- recoil
- React
- Promise
- 반공변성
- map
- autosize
- 결정 알고리즘
- dfs
- Cypress
- 무한 스크롤
- CI/CD
- 호이스팅
- SSR
- ESlint
- Today
- Total
짧은코딩
공변성과 반공변성(함수) 본문
어떤 함수는 다른 함수에 대입할 수 있는데, 대입이 불가능한 경우도 있다. 이를 제대로 이해하려면 공변성, 반공변성을 알아야 한다.
- 공변성: A->B일 때, T<A> -> T<B> 인 경우
- 반공변성: A->B일 때, T<B> -> T<A>인 경우
- 이변성: A->B일 때, T<A> -> T<B>도 되고 T<B> -> T<A>도 되는 경우
- 무공변성: A->B일 때, T<A> -> T<B>도 안 되고 T<B> -> T<A>도 안 되는 경우
TS는 기본적으로 공변성을 갖고 있지만, 함수의 매개변수는 반공변성을 갖는다!
그리고 TS Config에서 strict와 strictFunctionTypes가 모두 체크되어야 함수의 매개변수가 반공변성을 갖는다. 둘 다 체크되지 않으면 이변성을 갖는다.
반환값
a->b인 경우
function a(x: string): number {
return 0;
}
type B = (x: string) => number | string;
let b: B = a;
a 함수를 b 타입에 대입할 수 있고, 함수 반환값은 b가 더 넓은 타입이다.
(T 타입이 함수<반환값>이면)a->b일 때, 함수 a를 타입 b에 대입할 수 있기에 T<a> -> T<b>가 된다.
즉, 함수의 반환값은 공변성을 가진다.
b->a인 경우
function a(x: string): number | string {
return 0;
}
type B = (x: string) => number;
let b: B = a; // error
string | number를 number에 대입할 수 없다는 에러가 발생한다.
이때 strict 혹은 strictFunctionTypes를 해제해도 에러가 발생한다. 이는 반환값에 대해서는 항상 공변성을 가진다고 볼 수 있다.
매개변수
매개변수는 strict 옵션에서 반공변성을 가진다.
-b->a일 때
function a(x: string | number): number {
return 0;
}
type B = (x: string) => number;
let b: B = a;
매개변수가 string -> string | number라서 b->a인 상황이다.
그런데 a를 b에 대입할 수 있다. b->a에서 T<a> -> T<b>라서 매개변수가 반공변성을 가지고 있다.
-반대의 경우
function a(x: string): number {
return 0;
}
type B = (x: string | number) => number;
let b: B = a;
반대는 불가능하다. 따라서 매개변수는 반공변성을 가진다.
하지만 strict 옵션을 해제하면 에러가 발생하지 않는다. strict 옵션을 해제하면 이변성을 가지기 때문이다.
-결론
매개변수는 반공변성 또는 이변성을 가진다!
객체의 메서드 타이핑에 따른 변성
아래 예시는 strict 옵션이 활성화된 상태이다.
interface SayMethod {
say(a: string | number): string;
}
interface SayFunction {
say: (a: string | number) => string;
}
interface SayCall {
say: {
(a: string | number): string;
}
}
const sayFunc = (a: string) => "hello";
const MyAddingMethod:SayMethod = {
say: sayFunc // 이변성
}
const MyAddingFunction: SayFunction = {
say: sayFunc // 반공변성
}
const MyAddingCall: SayCall = {
say: sayFunc // 반공변성
}
sayFunc 함수는 (a: string) => string 타입을 가진다. 매개변수 반공변성에 의해 (a: string | number) => string에 대입할 수 없다.
하지만 "함수(매개변수): 반환값"으로 선언한 것은 매개변수가 이변성을 가진다.
"함수: (매개변수) => 반환값"으로 선언한 것은 반공변성을 가진다.
'TS > TS(with ZeroCho)' 카테고리의 다른 글
브랜드 속성 & 타입 좁히기 (1) | 2023.11.12 |
---|---|
infer로 타입 추론(with 컨디셔널 타입) (0) | 2023.11.11 |
오버로딩(any를 써야하는 경우!) (0) | 2023.09.28 |
타입을 집합으로 생각하자 (0) | 2023.09.15 |
React with TS (0) | 2022.09.12 |