0

问候。

所以我正在尝试打字稿。我基于的初始代码是在 javascript 上

const PokemonTable = () => {
  const pokemon = useStore((state) => state.pokemon);
  const filter = useStore((state) => state.filter);

  return (
    <table width="100%">
      <tbody>
        {pokemon
          .filter(({ name: { english } }) =>
            english.toLowerCase().includes(filter.toLowerCase())
          )
          .map(({ id, name: { english }, type }) => (
            <tr key={id}>
              <td>{english}</td>
              <td>{type.join(", ")}</td>
            </tr>
          ))}
      </tbody>
    </table>
  );
};

当我将其更改为打字稿时,它会引发这些错误

错误

我试图创建一个接口来将道具传递给它

//interfaz de pokemon table
interface PkTableProps{
  id:number,
  name:Array<String>,
  type:Array<String>,
}

然后我应用到箭头函数

// pokemon table

const PokemonTable = (props : PkTableProps) => {
  const pokemon = useStore((state) => state.pokemon);
  const filter = useStore((state) => state.filter);

  return (
    <table width="100%">
      <tbody>
        {pokemon
          .filter(({ props.name : { english } }) =>
            english.toLowerCase().includes(filter.toLowerCase())
          )
          .map(({ id, props.name: { english }, props.type }) => (
            <tr key={props.id}>
              <td>{english}</td>
              <td>{props.type.join(", ")}</td>
            </tr>
          ))}
      </tbody>
    </table>
  );
};

我得到了这些新的语法错误

错误

笔记

<td>{english}</td>箭头函数表上的行。我这样做是因为我试图用英语选择每个口袋妖怪的名字。这意味着我想要它key

这是我正在使用的口袋妖怪数组的结构
https://gist.githubusercontent.com/jherr/23ae3f96cf5ac341c98cd9aa164d2fe3/raw/0658aeff401d196dece7ec6fe6c726c6adc1cc00/gistfile1.txt

这是完整的代码

import React from "react";
import "./App.css";
import create from "zustand";
// import { mountStoreDevtool } from 'simple-zustand-devtools';

const POKEMON_URL =
  "https://gist.githubusercontent.com/jherr/23ae3f96cf5ac341c98cd9aa164d2fe3/raw/f8d792f5b2cf97eaaf9f0c2119918f333e348823/pokemon.json";

// definir el tipo de mi store
type State = {
  filter: string;
  pokemon: Array<string>;
  setFilter: (filter: string) => void;
  setPokemon: (pokemon: Array<string>) => void;
};

//interfaz de pokemon table
interface PkTableProps{
  id:number,
  name:Array<String>,
  type:Array<String>,
}


//tienda de estados
const useStore = create<State>((set) => ({
  // set initial values here
  filter: "",
  pokemon: [],

  setFilter: (filter: string) =>
    set((state) => ({
      ...state,
      filter,
    })),

  setPokemon: (pokemon: Array<string>) =>
    set((state) => ({
      ...state,
      pokemon,
    })),
}));

// if (process.env.NODE_ENV === 'development') {
//   mountStoreDevtool('Store', store);
// }

//  input
const FilterInput = () => {
  const filter = useStore((state) => state.filter);
  const setFilter = useStore((state) => state.setFilter);
  return (
    <input value={filter} onChange={(evt) => setFilter(evt.target.value)} />
  );
};

// pokemon table

const PokemonTable = (props : PkTableProps) => {
  const pokemon = useStore((state) => state.pokemon);
  const filter = useStore((state) => state.filter);

  return (
    <table width="100%">
      <tbody>
        {pokemon
          .filter(({ props.name : { english } }) =>
            english.toLowerCase().includes(filter.toLowerCase())
          )
          .map(({ id, props.name: { english }, props.type }) => (
            <tr key={props.id}>
              <td>{english}</td>
              <td>{props.type.join(", ")}</td>
            </tr>
          ))}
      </tbody>
    </table>
  );
};


function App()  {
  const setPokemon = useStore((state) => state.setPokemon);
  

  //lifecycle hook every time the component renders

  React.useEffect(() => {
    fetch(POKEMON_URL)
      .then((resp) => resp.json())
      .then((pokemon) => setPokemon(pokemon));
  });

  return (
    <div className="App">
      <div>
        <FilterInput />
      
      </div>
      <h1>List of Pokemons</h1>
      <PokemonTable />
      {/* mostrar el resultado de filter */}
      {/* {filter}   */}
      {/* mostar lo que el contenido del array de la url */}
      {/* {JSON.stringify(pokemon)} */}
    </div>
  );
}

export default App;
4

1 回答 1

0
type State = {
  filter: string;
  pokemon: Array<string>;
  setFilter: (filter: string) => void;
  setPokemon: (pokemon: Array<string>) => void;
};

这种类型表示pokemon您的商店的属性是一个数组String(应该是小写的string)。

pokemon.filter(({ name: { english } }) =>

此函数将pokemon数组的每个元素视为具有name属性的对象。name本身就是一个object带有一个属性的englisha string

这是两种不同且不兼容的类型,这就是您遇到错误的原因。


你需要弄清楚哪个是正确的,哪个是错误的。链接.txt文件对此有所帮助。口袋妖怪对象如下所示:

{
  id: 1,
  name: {
    english: "Bulbasaur",
    japanese: "フシギダネ&quot;,
    chinese: "妙蛙种子",
    french: "Bulbizarre"
  },
  type: ["Grass", "Poison"],
  base: {
    HP: 45,
    Attack: 49,
    Defense: 49,
    "Sp. Attack": 65,
    "Sp. Defense": 65,
    Speed: 45
  }
};

所以我们可以看到该name属性是一个具有属性的对象english——而不是一个Array<string>.

这取决于你想对你的类型有多具体。您可以将name属性描述为

type Name = Record<string, string>

这是一个对象,其键和值都是string. 这意味着任何string都可以用作密钥。所以你可能想更具体一点,说它是一个看起来像这样的对象:

type Name = {
  english: string;
  japanese: string;
  chinese: string;
  french: string;
}

如果您尝试访问无效的密钥,这会给您一个错误,例如name.spanish.


你的pokemon属性State是一个Array但它不是一个数组string——它是一个口袋妖怪对象的数组。我们需要Pokemon根据您的数据文件定义 a 的类型。

type Pokemon = {
  id: number;
  name: {
    english: string;
    japanese: string;
    chinese: string;
    french: string;
  };
  type: Array<string>;
  base: {
    HP: number;
    Attack: number;
    Defense: number;
    "Sp. Attack": number;
    "Sp. Defense": number;
    Speed: number;
  }
}

您的State类型可以使用这种Pokemon类型:

type State = {
  filter: string;
  pokemon: Array<Pokemon>;
  setFilter: (filter: string) => void;
  setPokemon: (pokemon: Array<Pokemon>) => void;
};

<State>由于您在函数上使用泛型create,因此可以通过删除参数上的类型来修复弹出的错误。它们将从您的State类型中正确推断出来。

const useStore = create<State>((set) => ({
  // set initial values here
  filter: "",
  pokemon: [],

  setFilter: (filter) =>
    set((state) => ({
      ...state,
      filter,
    })),

  setPokemon: (pokemon) =>
    set((state) => ({
      ...state,
      pokemon,
    })),
}));

在您的第一个版本中,PokemonTable没有使用任何道具。这个更接近正确。所以你可以删除你的PkTableProps界面。您需要的所有数据都来自商店而不是道具。

现在State有了正确的类型,您的初始PokemonTable组件就可以工作了!

const PokemonTable = () => {
  const pokemon = useStore((state) => state.pokemon);
  const filter = useStore((state) => state.filter);

  return (
    <table width="100%">
      <tbody>
        {pokemon
          .filter(({ name: { english } }) =>
            english.toLowerCase().includes(filter.toLowerCase())
          )
          .map(({ id, name: { english }, type }) => (
            <tr key={id}>
              <td>{english}</td>
              <td>{type.join(", ")}</td>
            </tr>
          ))}
      </tbody>
    </table>
  );
};

的嵌套解构.filter(({ name: { english } })可能难以阅读。这样写可能更容易理解。

const PokemonTable = () => {
  const pokemonArray = useStore((state) => state.pokemon);
  const filter = useStore((state) => state.filter);

  return (
    <table width="100%">
      <tbody>
      {pokemonArray
          .filter(pokemon =>
            pokemon.name.english.toLowerCase().includes(filter.toLowerCase())
          )
          .map((pokemon) => (
            <tr key={pokemon.id}>
              <td>{pokemon.name.english}</td>
              <td>{pokemon.type.join(", ")}</td>
            </tr>
          ))}
      </tbody>
    </table>
  );
};

最后一件事——您只需要useEffect获取 pokemon 数据的程序运行一次。你可以给它一个空的依赖数组[]或一个带有[setPokemon].

工作代码沙盒链接

于 2021-06-21T23:51:51.070 回答