【问题标题】:Declaring string type only works with as-syntax (TypeScript - React)声明字符串类型仅适用于 as-syntax (TypeScript - React)
【发布时间】:2021-02-02 14:34:27
【问题描述】:

我正在尝试使用 React 中的 TypeScript 将字符串类型分配给“播放器”,但它不能像选项 1 中那样简单地使用 player: string

选项 1:

Object.values(data.val()).forEach((player: string) => {
          newPlayers.push(player);
        });

上述方式产生一个ts err:

'(player: string) => null' 类型的参数不能分配给'(value: unknown, index: number, array: unknown[]) => null' 类型的参数。 参数 'player' 和 'value' 的类型不兼容。 类型 'unknown' 不可分配给类型 'string'.ts(2345)

但使用 as 语法,如下所示,可以更正它。这是为什么呢?

选项 2:

DB_players.once('value', (data) => {
      
      // Fetch players who signed up
      const newPlayers: string[] = [];

      if (data.val() ) {
        Object.values(data.val()).forEach((player) => {
          newPlayers.push(player as string); 
        });

        setPlayers(newPlayers); // save the new player list
      }
    });

【问题讨论】:

  • 没有多大意义。如果循环的主要目的是将项目推送到外部数组,为什么要使用 map?还要记住 player 类型是继承的,前提是您输入了 data.val()
  • 我正在使用 map 循环遍历一个对象(来自 Firebase)以仅获取值并将它们推送到 newPlayers。然后使用newPlayers 更新状态。
  • 如果您没有返回任何内容,您应该始终使用forEach 在此循环之前newPlayers 中是否已经有任何数据?如果不是,那么newPlayers 应该是从这个map 创建的数组。但主要问题是data.val() 的类型是unknown[],所以修复它。

标签: reactjs typescript types


【解决方案1】:

您的 map 函数中 player 的类型不是您应该分配的。类型来自您要映射的数组的元素类型。

Typescript 认为data.val() 返回的对象的值是unknown 类型。这是您需要修复的错误。最好在创建data 对象的代码中将其修复得更高,方法是说data.val() 返回Record<string, string> 或其他带有字符串值的类型。作为创可贴,您可以通过编写 (Object.values(data.val()) as string[]) 告诉 typescript 您正在将其用作字符串数组,这样您的错误就会消失。

与打字稿错误无关,@kind 用户是对的,如果您没有返回任何内容,则不应使用 map。如果newPlayers 是一个现有数组,其中已经包含您要添加的数据,那么您可以保留您的push,但在forEach 循环中执行此操作。如果这是您创建newPlayers 数组的位置,并且它为data.val 中的每个玩家提供一个条目,那么您可以从map 的返回值创建它——除非您实际上没有进行任何映射在这里,您只是返回相同的值。

这个单行代码与您的循环执行相同的操作,即将data.val() 中的所有名称附加到现有数组。 ... 表示它们将作为单独的条目添加。

newPlayers.push( ...Object.values(data.val()) as string[] );

如果您发布更多代码 -- data 来自哪里以及 newPlayers 是在哪里初始化的,那么我可以给您一个更好的解决方案。

编辑:

创建数组,直接使用对象值即可。

const newPlayers = Object.values(data.val()) as string[];

setPlayers( Object.values(data.val() ) as string[] );

【讨论】:

  • 感谢琳达的回复。 newPlayers 变量在循环之前已经为空。我没有声明数据类型,因为 ts 没有强加它,所以我认为这与 Firebase 有关。我将更新帖子以向您展示整个功能。
  • 那我想你只需要const newPlayers: string[] = Object.values(data.val());
  • 我对 firebase 并不特别熟悉,但通常当您获取数据时,您可以使用泛型来指定数据类型,例如 const data = fetchData<MyInterface>( args ),因此 data 是 @ 类型的承诺987654345@
  • 是的,解决了它。所以我用const newPlayers: string[] = Object.values(data.val());map返回玩家。
  • 谢谢你,琳达
【解决方案2】:

问题是 Object.values(data.val()) 不返回字符串数组。

当您在箭头函数中跳过播放器类型时,它被隐式视为任何类型,这与您尝试迭代的类型兼容。

const newPlayers: string[] = [];
let toto = {a: "test", b: "hello"};
Object.values(toto).map((player: string) => {
    newPlayers.push(player);
});

Playground

【讨论】:

  • 这是对的,但@Badr 要弄清楚的重要问题是为什么 Object.values 不在其代码中返回字符串。在您的示例中,player: string 是不必要的,因为它确实根据您的对象 toto 的值返回字符串。
  • 不知道 data 或 data.val() 是什么样子,我不知道。例如,可以通过使用 (Object.values(data.val()) as string[] 来强制它,但我认为最好将 data.val() 的类型固定为 Record跨度>
  • 我看到你的回答@LindaPaiste 并投了赞成票,它是完整的:)
猜你喜欢
  • 2020-01-07
  • 1970-01-01
  • 2012-03-19
  • 1970-01-01
  • 2023-03-29
  • 1970-01-01
  • 1970-01-01
  • 2022-11-30
  • 1970-01-01
相关资源
最近更新 更多