useData
라는 데이터 페칭 함수가 있다.
getData
를 반환하여 페칭한 값을 가져오는데
inititalData
를 넘긴 경우는 초기값이 있는데도 inititalData
가 옵셔널이기 때문에 number | undefined
로 추론된다.
이 문제를 해결하기 위해서 함수 오버로드가 필요하다.
반환값 getData
가 T | undefined
이기 때문인데 함수 오버로드를 해주자
첫 번째 오버로드는 inititalData
가 없는 경우다. inititalData
가 없으면 getData
는 T | undefined
를 반환한다.
두 번째 오버로드는 inititalData
가 있는 경우다. 이 경우 getData
는 T
만 반환한다.
이렇게 오버로드를 추가해주고 다시 inititalData
가 있었던 경우를 보면 제대로 추론하고 있음을 확인할 수 있다.
이러한 패턴은 복수개의 call signature를 가진 함수의 타입을 제어할 때 용이하다. 예를들어useQuery
에서도 이런 패턴이 적용되었다 (실제 react-query에서 적용된 pr)
이런 obj
가 있다.
ObjKey
는 키만 추출한 타입이다.
그리고 getValue
가 있다. getValue
에서 TKey
를 extends ObjKey
하였다. 하지만 보는 것처럼 기본값에서 무언가 문제가 생긴다.
기본값 테스트만 통과하지 못하는 상황.
한편 기본값으로 지정한 타입에선 이런 에러가 나온다. 문제를 해결해보자
에러의 원인은 제네릭 기본값 한계때문이다. TKey
는 'a' | 'b' | 'c'
의 서브타입이 될 수 있다. 즉, TKey
가 'b'
(혹은 'c')로 추론되면 "a"
는 타입이 깨진다.
즉, 기본값 "a"
가 모든 가능한 TKey
서브타입을 만족하지 못한 것이다.
이런 상황을 함수 오버로드로 해결할 수 있다. 인자가 들어온 경우를 먼저 추가해주고
인자가 없이 기본값으로 하는 경우를 추가해준다.
그리고 반환값에 기본값인 "a"로 인덱싱해준다.
이렇게 두 가지 케이스를 먼저 작성하고 기존에 있던 함수를 수정해준다.
먼저, 제네릭한 파트는 오버로딩한 함수에서 처리하고 있으니 제네릭을 제거한다.
구현 시그니처와 호환되지 않는다는 에러가 나온다. 기본값을 추가해서 호환하게 해주면된다.
ObjKey
에 기본값 'a'
를 추가했다.
테스트 모두 통과!
인자가 없을 경우, 기본값으로 오버로드된 타입을 타고
인자가 있다면, 제네릭으로 오버로드된 타입을 타게된다.
참고 : total typescript