React中使用useRef更新state遇TypeScript‘对象可能为null’问题
解决useRef与TypeScript的"object is possibly null"问题
针对你遇到的情况,这里有几个实用的TypeScript解决方案,无需每次都加冗余的if判断:
1. 可选链+类型守卫(最安全)
通过可选链?.和条件判断同时校验ref和offsetParent的有效性,TypeScript会自动缩小类型范围,消除提示:
const jselectRef = useRef<HTMLButtonElement>(null) const [defaultHeight, setDefaultHeight] = useState<number>(0) useEffect(() => { const button = jselectRef.current; // 同时校验button和offsetParent是否存在 if (button?.offsetParent) { setDefaultHeight(button.offsetParent.clientHeight) } }, []) // 后续使用defaultHeight时无需额外判断,因为初始值是0,后续赋值都是number return ( <> <button ref={jselectRef} style={{ height: dropdownOpen ? defaultHeight * 10 : defaultHeight }} > <div className="jselect__current" style={{ height: defaultHeight }}> </div> </button> </> )
2. 非空断言操作符(!)
如果你能100%确定组件挂载后button和它的offsetParent一定存在(比如按钮没有条件渲染、不会被设置为display: none),可以用非空断言跳过TypeScript的null检查:
useEffect(() => { if (jselectRef.current !== null) { // 用!断言offsetParent不为null setDefaultHeight(jselectRef.current.offsetParent!.clientHeight) } }, [])
注意:这个方法要谨慎使用,如果运行时offsetParent实际为null,会抛出错误。
3. 初始化时断言ref非空
如果按钮是页面固定渲染的元素(无条件渲染),可以在useRef初始化时就断言它不会为null,避免后续每次都检查current:
// 用null!断言初始值非空,TypeScript会认为current永远是HTMLButtonElement const jselectRef = useRef<HTMLButtonElement>(null!) useEffect(() => { // 无需再检查jselectRef.current是否为null if (jselectRef.current.offsetParent) { setDefaultHeight(jselectRef.current.offsetParent.clientHeight) } }, [])
4. 自定义类型守卫
如果需要更复杂的类型校验,可以写一个自定义类型守卫函数,让TypeScript明确知道变量的有效状态:
// 自定义类型守卫,判断元素是否存在且有offsetParent function isValidButton(el: HTMLButtonElement | null): el is HTMLButtonElement { return el !== null && el.offsetParent !== null } const jselectRef = useRef<HTMLButtonElement>(null) const [defaultHeight, setDefaultHeight] = useState<number>(0) useEffect(() => { if (isValidButton(jselectRef.current)) { // TypeScript会自动推断jselectRef.current和offsetParent都不为null setDefaultHeight(jselectRef.current.offsetParent.clientHeight) } }, [])
另外,不要把defaultHeight的类型改成number | undefined——你的初始值是0,后续只会被赋值合法的number,TypeScript完全可以信任它的类型就是number,改类型反而会引入不必要的undefined判断。
内容的提问来源于stack exchange,提问作者Josh Silveous
相关产品推荐
相关产品推荐

