You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 10:50:22