❗️ 문제
로그인, 회원가입 폼에 애니메이션을 트리거하기 위해서 만든 useRef에 타입을 줘야 했다.
본질적으로 useRef는 .current 프로퍼티에 변경 가능한 값을 담고 있는 “상자”와 같다.
처음엔 이런 형태로 타입을 부여했었다.
const inputRef = useRef<HTMLInputElement>(null);
그런데 인풋의 ref 속성으로 부여된 useRef 값의 current에 접근할 수 없는 문제가 생겨서 그 이유를 살펴보았다.
🔎 원인
useRef 훅은 3개의 정의가 오버로딩되어 있다.
1. useRef<T>(initialValue: T): MutableRefObject<T>;
인자의 타입과 제네릭의 타입이 T로 일치하는 경우, MutableRefObject<T>를 반환한다.
MutableRefObject<T>의 경우, 이름에서도 볼 수 있고 위의 정의에서도 확인할 수 있듯 current 프로퍼티 그 자체를 직접 변경할 수 있다.
2. useRef<T>(initialValue: T|null): RefObject<T>;
인자의 타입이 null을 허용하는 경우, RefObject<T>를 반환한다.
RefObject<T>는 위에서 보았듯 current 프로퍼티를 직접 수정할 수 없다.
3. useRef<T = undefined>(): MutableRefObject<T | undefined>;
제네릭의 타입이 undefined인 경우(타입을 제공하지 않은 경우), MutableRefObject<T | undefined>를 반환한다.
정의로 보면 다음과 같이 생겼다.
interface MutableRefObject<T> {
current: T;
}
interface RefObject<T> {
readonly current: T | null;
}
중요한 건 MutableRefObject은 current가 수정 가능하지만 RefObject는 readonly가 붙어있어서 불가능하는 것이다. 즉 초기값으로 null을 보냈기 때문에 current에 접근이 안 됐었다.
🎉 해결
간단히 3번 오버로드를 사용하는 것으로 해결했다.
const inputRef = useRef<HTMLInputElement>();
초기값을 비워서 undefined로 타입을 부여하면 뮤터블 하게 사용이 가능했다.