React Typescript 解构 providerValue

IT技术 reactjs typescript
2021-04-28 06:47:05

在我上一篇关于如何传递setState给上下文 API 的子项的成员的建议之后,我有以下代码:


export interface IShowProviderProps {
    shows: IShow[];
    setShows: (currentShows: IShow[], shows: IShow[]) => void;
    sort: string;
    setSort: (sort: string) => void;
    query: string;
    setQuery: (sort: string) => void;
    showType: string;
    setShowType: (sort: "movie" | "tv") => void;
    page: number;
    setPage: (page: number) => void;
}

export const ShowContext = createContext<IShowProviderProps | null>(null);

export const ShowProvider = ({ children }: Props): JSX.Element => {
    const [shows, setShows] = useState<IShow[]>([]);
    const [sort, setSort] = useState<string>("popularity.desc");
    const [query, setQuery] = useState<string>("");
    const [showType, setShowType] = useState<"movie" | "tv">("movie");
    const [page, setPage] = useState<number>(1);

  const providerValue: IShowProviderProps = {
        shows,
        setShows,
        sort,
        setSort,
        query,
        setQuery,
        showType,
        setShowType,
        page,
        setPage
    };

 return <ShowContext.Provider value={providerValue}>{children}</ShowContext.Provider>;

export const useShows = () => useContext(ShowContext);

当我对孩子们使用上下文时,我会尝试这样的事情

 const {shows, setShows} = useShows();

我得到错误:

IShowProviderProps 类型上不存在属性“shows” | 空值

我必须这样做:

 const providerValues = useShows();

然后 providerValues?.shows(没有?我可能为空)

我该怎么办?谢谢

2个回答

我不使用 TypeScript,所以我的回答可能不是很准确,但这一行

const ShowContext = React.createContext<IShowProviderProps>({} as IShowProviderProps);

解决了这个问题。问题是,由于providerValues can be null,TS 编译器假定null必须具有shows,而它显然没有。

逻辑上没有任何问题。我认为这IShowProviderProps | null是一种在您null作为初始值传递时保持 TS 编译器静音的解决方法

我把你所有的代码都放在了一个codeandbox 中,检查一下 - 一切正常。

顺便说一句,我相信setShows: (currentShows: IShow[], shows: IShow[]) => void;是一个错误的签名setShows这需要这或者是一个唯一的参数IShowIShow => IShow,但不是两个。

这里的问题是您的 Context 的值类型是IShowProviderProps之间的联合null

/* The "IShowProviderProps | null" means that the value can be of type
   IShowProviderProps or type null */
export const ShowContext = createContext<IShowProviderProps | null>(null);

因此,TypeScript 会将您的 Context 的值视为潜在的值,null并且默认情况下,当您尝试访问(可能)null值的字段时,将报告编译错误

/* Obtain context value - note that the value type is for this is
   IShowProviderProps | null, which means TypeScript sees showsValue
   as being potentially null */
const showsValue = useShows(); 

/* TypeScript won't allow access to shows, setShows, on a nullable value */
const {shows, setShows} = showsValue;

这里的一种解决方案是简单地将 Context 的值类型定义为IShowProviderProps

/* Removing "| null" causes TypeScript to now consider the value type of 
   ShowContext to be non-nullable, ie always defined */
export const ShowContext = createContext<IShowProviderProps>(null);

有了这个变化,在运行时对上下文值的任何“空检查”的需求都可以被忽略,因为 TypeScript 会推断 Context 值总是被定义为 type IShowProviderProps

要使这些更改生效,您需要确保禁用 TypeScripts“严格模式”。这可以通过确保"strict" : false存在于compilerOptions您的项目tsconfig.js文件中来完成:

{
  "compilerOptions": {
    ...

    "strict": false,

    ...
  },
  ...
}

希望有帮助!