现上段代码:
import { useRef } from "react";
const Main = () => {
// useRef 没有传入参数,也就是传入了 undefined
// 查看 divRef 的类型。
// const divRef: React.MutableRefObject<HTMLDivElement | undefined>
const divRef = useRef<HTMLDivElement>();
return (
<div>
// 查看 div 的 ref 属性的类型
// React.LegacyRef<HTMLDivElement> | undefined
<div ref={divRef}>useRef and null</div>
</div>
);
};
export default Main;
在 vscode 可以看到代码是有报错的:
不能将类型React.MutableRefObject<HTMLDivElement | undefined>
分配给类型React.LegacyRef<HTMLDivElement> | undefined
最终不兼容的是 current:不能将类型HTMLDivElement | undefined
分配给类型HTMLDivElement | null
后面再分析原因,先看解决方法
接着在 useRef 传入 null:
import { useRef } from "react";
const Main = () => {
// const divRef: React.RefObject<HTMLDivElement>
const divRef = useRef<HTMLDivElement>(null);
return (
<div>
// React.LegacyRef<HTMLDivElement> | undefined
<div ref={divRef}>useRef and null</div>
</div>
);
};
export default Main;
可以看到报错没有了。
其实 useRef 传不传入null,都可以正常运行(可以在 js 里测试),错误是 ts 报的类型问题。
报错原因分析,查看 useRef ts 声明文件,看到如下定义:
interface RefObject<T> {
readonly current: T | null;
}
interface MutableRefObject<T> {
current: T;
}
function useRef<T>(initialValue: T|null): RefObject<T>;
function useRef<T = undefined>(): MutableRefObject<T | undefined>;
找到了 useRef 的两份声明,根据是否有传入参数,决定了返回值的类型。
查看 ref 属性声明
interface RefObject<T> {
readonly current: T | null;
}
type RefCallback<T> = { bivarianceHack(instance: T | null): void }["bivarianceHack"];
type Ref<T> = RefCallback<T> | RefObject<T> | null;
type LegacyRef<T> = string | Ref<T>;
interface ClassAttributes<T> extends Attributes {
ref?: LegacyRef<T>;
}
- 所以不传入 null 时,useRef 返回值的类型为
MutableRefObject<T | undefined>
,current 的类型为T | undefined
- 注意
MutableRefObject<T | undefined>
中,T | undefined
整体传入interface MutableRefObject<T>
,所以interface MutableRefObject<T>
中T的类型为T | undefined
,所以 current 的类型为T | undefined
- 注意
- 而 ref 属性想要的类型为
RefObject<T>
,current 的类型为T | null
T | undefined
与T | null
类型不兼容