함수의 공변성과 반공변성에 대한 이유 설명
814
작성한 질문수 1
질문은 아니지만 다른 분들도 쉽게 보시고 이해하실 수 있도록 해당 수업의 질문으로 남기도록 하겠습니다.
설명에 앞서 그냥 강사님께서 하신 말씀처럼 외우는게 제일 나을수도 있습니다. 그냥 저처럼 이해하지 못하면 못 넘어가는 사람들을 위해 남깁니다.
공변성과 반공변성에 대하여 매개변수와 리턴타입의 대입가능성에 대해 설명하고자 합니다. 강의에서 사용된 예제를 사용하겠습니다.
function a(x: string | number): number{
return 0;
}
type B = (x: string) => number | string;
let b: B = a;
b("asdf") // B타입에 맞음 정상
b(123) //B타입에 맞지 않는 매개변수 이므로
//typescript가 오류를 잡아줄 수 있음먼저 매개변수에 대한 이야기입니다. 변수 b의 B 타입으로 정의되었습니다. 즉, 매개변수로는 x: string만 오도록 강제할 것입니다. 이는 b("asdf")로 사용했을 때 a("asdf")를 사용한 것과 같은 상황이니 문제가 없습니다. 하지만 반대면 어떨까요?
function a(x: string): number{
return 0;
}
type B = (x: string | number) => number | string;
let b: B = a;
b("asdf") // 타입 B에 대해서도 정상
//a함수가 실행될때도 정상
b(123); // B타입상으로만 보면 정상임
//그러나 실제로 a함수가 실행될 때 오류
//따라서 이런 상황이 발생하지 않도록
//타입스크립트는 타입B에 함수 a를 할당할 수 없도록 함만약 이 상황이라면 변수 b는 B타입이기 때문에 매개변수로 number도 사용하능 합니다. 즉 타입상으로는 b(123)이 가능하다는 것이죠, 하지만 이 경우 a(123)이 실행되는 것과 같은데 a의 매개변수로는 string만 가능하기 때문에 문제가 발생합니다.
정리하자면 실제로 대입된 함수의 매개변수가 허용하지 않는 타입을 넣으면 안 되기 때문에, (대입되는 함수의 매개변수)는 (타입의 매개변수)와 같거나 더 넓어야합니다.
리턴값도 비슷한 원리입니다.
function a(x: string | number): number{
return 0;
}
type B = (x: string) => number | string;
let b: B = a;
let result = b("asdf");
//result의 타입은 B타입에 의해 number|string 으로 추론됨
//실행결과 실제 타입은 number로 추론과 일치타입스크립트 입장에서 b("asdf")의 예상 결과는 number | string 이겠죠. b는 타입 B 니까요. 그리고 실제로 b("asdf")는 실제로 a("asdf")를 실행하는 것과 같으니 실제로는 number가 리턴됩니다. 타입스크립트는 number | string를 예상하고 있고, 거기에 number가 온 것이니 문제가 없습니다.
반대 상황을 봅시다.
function a(x: string | number): number | string {
return 0;
}
type B = (x: string) => number;
let b: B = a;
let result = b("asdf");
//타입 B만 보고 추론하면 result는 number임
//근데 실제 실행결과로 result는 string이 될 수도 있음타입스크립트는 b("asdf")의 결과로 number 만을 기대할 것입니다. 근데 실제로 a("asdf")는 number | string 이에요. 그러면 원래는 b의 실행결과로는 number만 예상하고 있었는데 실제 결과로 number | string 이면 문제가 있겠죠?
정리하자면 실제로 대입된 함수가 리턴한 값이 타입의 리턴값에 포함되지 않으면 안 되기 때문에, (대입되는 함수의 리턴값)는 (타입의 리턴값)와 같거나 더 좁아야합니다.
위 모든 원칙은, 타입스크립트가 실제로 대입된 함수의 타입은 신경쓰지 않고, 현재 정의된 타입이 뭔지만 신경쓰기 위해서 존재한다고 생각하시면 이해가 편하실수도 있을 것 같네요...
타입스크립트의 타입검사기 입장에서
let b: B = a;이후에 b를 쓸 때, a에 대해서 신경1도 안쓰고 B에 대해서만 타입 검사를 해주려고 처음 대입할때 매개변수의 범위와 리턴값의 범위를 저렇게 제한했다고 보시면 된다는 뜻입니다.
데코레이터가 현재도 자주 쓰이는 문법인가요?
0
76
2
유틸리티 타입 실제로 구현은 못해도 하나씩 외우면 실무할 때 지장 없겠죠?
0
63
1
매핑 타입은 type에서밖에 안된다고 하네요?
0
62
2
자바에서의 오버로딩과 같은 개념이라고 생각해도 되나요?
0
67
2
filter 함수 반환 타입 네로잉 질문
0
65
2
map<U>(callbackfn: ....) 할때 U는 왜 여기 있는거에요??
0
44
2
ts 컴파일을 위한 type 라벨링 부분
0
44
1
concat 함수 타입 구현 중 질문 있습니다!
0
99
2
filter 메소드 질문
0
52
1
forEach 제네릭 관련 문의
0
59
1
타입 추론 시 가장 넓은 범위로 추론이 되는 건가요?
0
162
1
enum이 javascript로 트랜스파일링될때 사라진다하셨는데요
0
206
1
함수 파라미터 타입 정의 시 ...args: any[]와 ...args: any 의 차이
0
223
1
Flat type에서 ReadonlyArray 타입을 사용하는 이유?
0
156
1
bind type 질문
1
147
1
Lowercase type 관련 질문
0
151
1
key-value 타입 자동추론 질문드립니다
0
264
1
타입스크립트 교과서, p131
0
263
1
타입스크립트 교과서 p122 forEach 메서드 질문
0
231
1
타입스크립트 교과서 p116 , 코드에러남
1
268
1
타입스크립트 교과서 p112 , 코드가 안읽힙니다..
0
263
1
타입스크립트 교과서 p83
1
181
1
타입스크립트교과서 p39 쪽 코드가 이해가 안되요
1
223
1
class 에서 ts의 private vs js의 private field( # )
0
334
1





