首页 > 解决方案 > TypeScript React 中的对象可能为空

问题描述

使用此代码:

const Products = () => {
  const classes = useStyles();

  const { data } = useFetch('/categories');

  return (
    <div className={classes.root}>
      <GridList cellHeight={180} className={classes.gridList}>
        <GridListTile key="Subheader" cols={6} style={{ height: 'auto' }} />
        {data &&
          data.map((category: CategoryInterface) => {
            return (
              <GridListTile key={category.id}>
                <GridListTileBar title={category.name} />
              </GridListTile>
            );
          })}
      </GridList>
    </div>
  );
};

我在地图之前的数据上得到“对象可能为空”,我尝试使用 && 运算符来摆脱它,我还尝试定义一个变量,const categories = data as CategoryInterface[]但这表明我必须先转换为未知,我应该怎么做反而?

这是 useFetch 钩子

import { useEffect, useState } from 'react';

export const useFetch = (url: string) => {
  const [state, setState] = useState({ data: null, loading: true });

  useEffect(() => {
    setState(state => ({ data: state.data, loading: true }));

    fetch(url)
      .then(res => res.json())
      .then(json => setState({ data: json, loading: false }));
  }, [url, setState]);

  return state;
};

标签: reactjstypescript

解决方案


Typescript 将类型分配给 JavaScript 变量。大多数情况下,当您使用 TS 时,您应该在使用前定义变量类型。但是,如果可能,TS 有时可以推断变量的类型。

似乎您将 JS 代码复制粘贴到 TypeScript 中并试图使其工作。所以首先我建议为你要使用的变量定义类型,这样 TS 会设置正确的类型。

useState对makestate.data类型的初始调用null(这是唯一 TS 知道它的类型)。与 JS 不同,TS 不允许在执行期间更改类型。所以在程序执行期间state.data会有类型。null

const [state, setState] = useState({ data: null, loading: true });
// Type of state is
// { data: null, loading: boolean }

要纠正这个问题,您应该state提前提供变量的类型。它的一个可能值是null。另一个可能的值 - 是从 接收的数据fetch。您可能应该知道什么是返回数据的 JSON 类型结构,fetch因此请正确输入。

从您的代码中我可以猜到,该数据类型可能看起来像这样

type IData = CategoryInterface[];

可能CategoryInterface看起来像

interface CategoryInterface {
    id: string;
    name: string; 
}

所以IData将是第二种可能的类型state.data。所以在通话state期间分配类型useState

const [state, setState] = useState<{data: IData | null, loading: boolean}>({ data: null, loading: true });

但是你应该留在原地{data && data.map (/*...*/)}state.data直到数据完全加载。

完整代码

interface CategoryInterface {
    id: string;
    name: string;
}

type IData = CategoryInterface[];

export const useFetch = (url: string) => {
    const [state, setState] = useState<{ data: IData | null, loading: boolean }>({ data: null, loading: true });

    useEffect(() => {
        setState(state => ({ data: state.data, loading: true }));

        fetch(url)
            .then(res => res.json())
            .then(json => setState({ data: json, loading: false }));
    }, [url, setState]);

    return state;
};

推荐阅读