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

React搭配TypeScript使用useContext时有无Partial的替代方案

问题根源

你遇到的报错本质是Partial<contextTypes>会把接口中所有属性标记为可选,TypeScript默认所有从Context取出的属性都可能为undefined,调用函数类型的属性时就会触发「无法调用可能为undefined的对象」报错。你用Partial只是为了给createContext传初始空对象,但实际通过Provider注入的value是完整符合contextTypes定义的,这个矛盾导致了不必要的类型校验报错。

解决方案1(推荐:带运行时校验,类型安全)

我们可以抛弃Partial,封装专用的自定义Context钩子,同时实现类型安全和错误提示:

  1. 把Context的泛型改为contextTypes | undefined,初始默认值设为undefined
  2. 封装自定义的useContext钩子,在内部做非空判断,不符合条件就抛出明确错误
  3. 后续所有组件都用这个自定义钩子取Context,返回值自动是完整的contextTypes类型,不需要任何非空断言

修改后的完整代码如下:

import React, { useState, createContext, useContext } from 'react';
import endpoints from '../components/endpoints/endpoints';

interface contextTypes {
    endpointQuery: string,
    setEndpointQuery: React.Dispatch<React.SetStateAction<string>>,
    searchInput: string,
    setSearchInput: React.Dispatch<React.SetStateAction<string>>,
    filmSearch: string | undefined,
    setFilmSearch: React.Dispatch<React.SetStateAction<string>>, // 注意你原代码这里漏了逗号,记得补上
    pageIndex: number,
    setPageIndex: React.Dispatch<React.SetStateAction<number>>,
    resetState: () => void;
}

// 初始默认值设为undefined,泛型标注为联合类型
export const DisplayContext = createContext<contextTypes | undefined>(undefined);

// 封装专用的自定义钩子
export function useDisplayContext() {
  const context = useContext(DisplayContext);
  // 运行时校验:如果取到undefined说明组件没有被Provider包裹
  if (!context) {
    throw new Error("useDisplayContext 必须在 DisplayContextProvider 内部使用");
  }
  return context;
}

interface Props {
    children: React.ReactNode;
}

const DisplayContextProvider = (props: Props) => {
    const { nowShowing } = endpoints;
    const [ endpointQuery, setEndpointQuery ] = useState(nowShowing);
    const [ searchInput, setSearchInput ] = useState('');
    const [ filmSearch, setFilmSearch ] = useState('');
    const [ pageIndex, setPageIndex ] = useState(1);

    const resetState = () => {
        setSearchInput('');
        setFilmSearch('');
        setPageIndex(1);
    };

    const values = {
        endpointQuery,
        setEndpointQuery,
        pageIndex,
        setPageIndex,
        filmSearch,
        setFilmSearch,
        searchInput,
        setSearchInput,
        resetState
    };
    
    return (
        <DisplayContext.Provider value={values}>
            {props.children}
        </DisplayContext.Provider>
    );
};

export default DisplayContextProvider;

后续在组件中使用时直接调用useDisplayContext()即可,所有属性都是必选类型,不会触发undefined报错:

const { resetState, setSearchInput } = useDisplayContext();
// 直接调用不需要加!
resetState();

解决方案2(极简版:适合小型项目)

如果你能100%保证所有使用该Context的组件都会被Provider包裹,永远不会用到默认值,可以直接用类型断言把初始空对象标记为符合contextTypes类型,仅修改createContext一行即可:

export const DisplayContext = createContext<contextTypes>({} as contextTypes);

这个方案不需要改其他代码,但是没有运行时校验,如果确实出现组件没被Provider包裹的情况,会直接报属性未定义的运行时错误,排查成本更高。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.12 09:09:00