【问题标题】:Reactjs Typerscript: Property 'toLowerCase' does not exist on type 'never'Reactjs Typescript:“从不”类型上不存在属性“toLowerCase”
【发布时间】:2019-08-06 06:20:05
【问题描述】:

我正在尝试使用 tsx 在 reactjs 中过滤具有多个键值的数据。 Cards.tsx 是父组件,ShipmentCard.tsx 是子组件。我收到Property 'toLowerCase' does not exist on type 'never' 错误。我只想根据搜索条件返回相关对象。谁能让我知道我在哪里犯了错误?

Cards.tsx

class Cards extends Component {
  state = {
    card: [],
    filter: ""
  };

  componentDidMount() {
    this.loadShipmentList();
  }

  handleChange = (event: any) => {
    this.setState({ filter: event.target.value });
  };

  loadShipmentList() {
    fetch("http://localhost:3001/shipments")
      .then(response => response.json())
      .then(data => this.setState({ card: data }));
  }

  render() {
    const { card, filter } = this.state;
    const lowercasedFilter = filter.toLowerCase();
    const filteredData = this.state.card.filter(item => {
      return Object.keys(item).some(key =>
        item[key].toLowerCase().includes(lowercasedFilter)
      );
    });

    return (
        <Card className="Search-Bar">
          <CardContent>
            <Grid container spacing={3}>
                <TextField
                  label="Search"
                  onChange={this.handleChange}
                />
            </Grid>
          </CardContent>
        </Card>
        <Grid container spacing={3}>
          {filteredData.map((card: any) => (
            <Grid item xs={12}>
              <ShipmentCard key={card.id} value={card} />
            </Grid>
          ))}
        </Grid>
    );
  }
}

export default Cards;
db.json

{
  "shipments": [
    {
      "id": "123",
      "name": "Heromisha",
      "total": "1000",
      "status": "ACTIVE",
      "userId": "E222"
    },
    {
      "id": "456",
      "name": "Honda",
      "total": "3000",
      "status": "ACTIVE",
      "userId": "E111"
    }
  ]
}

【问题讨论】:

  • 什么时候出现这个错误,启动时?另外,我建议不要对变量使用“过滤器”这个词。
  • 注意到了。开始打字的时候。 TypeError: item[key].toLowerCase is not a function
  • @rrd - 没有理由不能使用 filter 作为变量名。
  • @T.J.Crowder,感谢您回来。我还在琢磨。 item[key].toLowerCase() 对象值和filter.toLowerCase() 是输入值。这是我得到TypeError: item[key].toLowerCase is not a function的错误
  • @SKL - 如果您执行我在答案末尾添加的操作,您将不会收到该错误。

标签: javascript reactjs typescript types react-tsx


【解决方案1】:

编译器不是 state.card[...] 的真实类型,因为它被声明为数组。 最简单的方法是将其声明为 any[]

  state = {
    card: [] as any[],
    filter: ""
  };

或显式描述数据类型

interface Card {
    "id": string,
    "name": string,
    "total": string,
    "status": string,
    "userId": string
}
...
      state = {
        card: [] as Card[],
        filter: ""
      };

或以对象为例

const cardSample = {
      "id": "123",
      "name": "Heromisha",
      "total": "1000",
      "status": "ACTIVE",
      "userId": "E222"
  };

type Card = typeof cardSample;

    ...
          state = {
            card: [] as Card[],
            filter: ""
          };

【讨论】:

  • @T.J.Crowder 我在操场上检查了代码,编译得很好
  • 我在没有输入 React 的情况下检查了 Playground。现在我已经在 react-create-app 创建的本地项目中检查了它,并且更改修复了错误“Property 'toLowerCase' does not exist on type 'never'”。
  • 不错!啊,我们正在谈论对toUpperCase 的不同调用! :-) 这解释了它。
【解决方案2】:

Component 是一个具有两个类型参数的通用接口:你的道具类型和你的状态类型。您的组件似乎没有 props,因此您可以将 object{} 用于 props 接口,但您确实有状态,因此您需要说明该状态具有什么 shape

interface Card {
  id:     string;
  name:   string;
  total:  string;
  status: string;
  userId: string;
}
interface CardsState {
  card:   Card[];
  filter: string;
}
class Cards extends Component<object,CardsState> {
  state: CardsState = {
    card: [],
    filter: ""
  };
  // ...
}

另外,我怀疑你会遇到的接下来的几个问题是:

  1. 您没有检查fetch 是否成功。你并不孤单,这是一个非常常见的错误(我在我贫血的小博客上wrote it up 很常见)。您需要在fetch 电话中添加支票:

    fetch("http://localhost:3001/shipments")
    .then(response => {
      if (!response.ok) {
        throw new Error("HTTP error " + response.status);
      }
      return response.json();
    })
    // ...
    
  2. 您没有处理来自fetch 的错误。 loadShipmentList 应该返回承诺链(然后 componentDidMount 和其他使用它的地方会处理错误)或自己处理/报告错误。

  3. 您将 card 设置为解析 JSON 的结果。您的代码假定 card 是一个数组,但 JSON 的顶层不是数组,它是一个具有 shipments 属性的对象(它是一个数组)。我怀疑您打算将card(应该是cards、复数或shipments)设置为返回数据的shipments 属性:

    .then(({shipments}) => this.setState({ card: shipments }));
    //    ^^         ^^                          ^^^^^^^^^
    

可能还有其他问题,但上面的主要答案应该解决 never 问题,希望这些进一步的提示有所帮助。


在评论中你说过当你给card 一个类型时,这个代码会导致错误:

const filteredData = this.state.card.filter(item => {
  return Object.keys(item).some(key =>
    item[key].toLowerCase().includes(lowercasedFilter)
  );
});

如果您希望 JSON 中数据的形状是可变的,您可以将 card 声明为 any[](或者可能是 Record&lt;string,string&gt;[]),然后该动态代码将起作用。但前提是您希望组件由 JSON 驱动。否则,更新代码以使用类型安全的属性名称:

const filteredData = this.state.card.filter(({id, name, total, status, userId}) =>
  `${id}\t${name}\t${total}\t${status}\t${userId}`.toLowerCase().includes(lowercasedFilter)
);

【讨论】:

  • 我对你的第三点很困惑。当我开始输入TypeError: item[key].toLowerCase is not a function 时抛出错误
  • @SKL - 我不确定这与我的第三点有何关系,但如果你想像这样动态访问 card 中条目的属性,你必须告诉 TypeScript 你想要这样做。这是一个相当基本的 TypeScript 事情,与 React 无关,并且离最初的问题有点远。关于这样做,我在答案的末尾添加了一些内容。
猜你喜欢
  • 2021-08-26
  • 2023-04-02
  • 2018-08-17
  • 1970-01-01
  • 2023-02-06
  • 2019-06-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多