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

Next.js SSR函数组件中Set State类型收窄问题(无需类型断言)

无需类型断言实现React useState Dispatch类型收窄

问题场景

现有一个接收Next.js SSR传递props的React函数组件,初始代码如下:

const Component = ({ err, n }: { err?: ErrorType; n?: N }) => {
    const [x, setX] = useState(n || null)
    // ...其他逻辑
    if(err){
        return <ErrorComponent err={err} />
    }
    else if(!(x===null)){
        return <SomeComponent setX={setX} />
    }
}

这里x的类型为N | null,通过条件判断可将其类型收窄为N,但setX的类型仍为Dispatch<SetStateAction<N | null>>,而SomeComponent要求传入的setX类型为Dispatch<SetStateAction<N>>。

尝试将useState放在条件判断后虽能解决类型问题,但违反了React Hook调用规则,抛出错误:React Hook "useState" is called conditionally. React Hooks must be called in the exact same order in every component render.


解决方案

方案1:包装符合类型要求的setter函数

在x类型已收窄的分支中,包装一个只接受N类型更新的函数,TypeScript会自动推导其类型为Dispatch<SetStateAction<N>>,无需断言:

const Component = ({ err, n }: { err?: ErrorType; n?: N }) => {
  const [x, setX] = useState(n || null);

  if (err) {
    return <ErrorComponent err={err} />;
  }

  if (x !== null) {
    // 包装出符合SomeComponent要求的setter
    const setXForComponent = (value: SetStateAction<N>) => {
      setX(value);
    };
    return <SomeComponent setX={setXForComponent} />;
  }

  // 处理x为null的边界情况,比如返回加载组件
  return <LoadingComponent />;
};

方案2:拆分组件分离校验与渲染逻辑

将props校验、错误处理与核心渲染逻辑拆分为两个组件,外层组件负责过滤无效props,内层组件只接收确定类型的参数,确保useState的类型正确:

// 内层组件:仅接收确定类型的初始值
const ComponentContent = ({ initialN }: { initialN: N }) => {
  const [x, setX] = useState(initialN);
  return <SomeComponent setX={setX} />;
};

// 外层组件:处理错误与props校验
const Component = ({ err, n }: { err?: ErrorType; n?: N }) => {
  if (err || n == null) {
    return <ErrorComponent err={err} />;
  }
  return <ComponentContent initialN={n} />;
};

内容的提问来源于stack exchange,提问作者Lucien950

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 04:45:22