Как передать массив объектов интерфейса TypeScript в качестве реквизита в компоненте React Child

Я изучаю реагировать и Typescript, Мне нужно передать объект интерфейса TypeScript от родительского к дочернему компоненту, если я удалю TypeScript и сделаю это в чистом React, это сработает.

Интерфейс TypeScript

export interface IUser {
  id: number;
  name: string;
  username: string;
  email: string;
}

Родитель.tsx

import { useEffect, useState } from "react";
import { IUser } from "./ApiInterface";
import Child from "./Child";
export default function App() {
  const [users, setUsers] = useState<IUser[]>();

  useEffect(() => {
    fetch(`https://jsonplaceholder.typicode.com/users`)
      .then((res) => res.json())
      .then((res) => setUsers(res as IUser[]));
  }, []);

  return <Child users = {users} />;
}

Ребенок.tsx

import { IUser } from "./ApiInterface";

const Child: React.FunctionComponent<IUser[]> = (users: IUser[]): JSX.Element => {
  return (
    <div>
      {users.map((u, i) => (
        <h1 key = {u.id}>{u.name}</h1>
      ))}
    </div>
  );
};
export default Child;

ошибка

ERROR in src/App.tsx:14:17
TS2322: Type '{ users: IUser[] | undefined; }' is not assignable to type 'IntrinsicAttributes & IUser[]'.
  Property 'users' does not exist on type 'IntrinsicAttributes & IUser[]'.
    12 |   }, []);
    13 |
  > 14 |   return <Child users = {users} />;
       |                 ^^^^^
    15 | }
    16 |

🤔 А знаете ли вы, что...
JavaScript может выполняться как на стороне клиента (в браузере), так и на стороне сервера (с использованием Node.js).


51
1

Ответ:

Решено

Вы используете неправильный тип для вашего дочернего компонента. Вы используете React.FC<IUser[]>, что означает, что ваш дочерний компонент ожидает массив объектов IUser в качестве реквизита, но вы передаете объект со свойством users, которое содержит массив объектов IUser.

Чтобы исправить это, вам нужно использовать правильный тип для вашего дочернего компонента и установить начальное значение для вашей переменной состояния users.

Например:

// define correct type for child component
interface ChildProps {
  users: IUser[];
}

const Child: React.FC<ChildProps> = ({ users }: ChildProps): JSX.Element => {
  return (...);
};


// initialize state value
const [users, setUsers] = useState<IUser[]>([]);

Вы можете увидеть весь пример здесь: codeandbox.io


ОБНОВЛЕННЫЙ ОТВЕТ

Вам не обязательно создавать новый интерфейс для каждого интерфейса, который вы хотите передать в качестве реквизита. Вы также можете указать тип вашего реквизита в строке, например @sai vineeth, предложенный в комментарии, или просто напрямую использовать существующий интерфейс.

Например:

const Child: React.FC<{ users: IUser[] }> = ({ users }: { users: IUser[] }): JSX.Element => { return (...); };

Но лучше создать интерфейс. Создание отдельного интерфейса для вашего реквизита может улучшить качество вашего кода, возможность повторного использования и согласованность.

В конечном счете, вы должны решить, что лучше всего подходит для вас и вашей ситуации, но я думаю, что это хорошая идея, когда это возможно, создавать отдельный интерфейс для ваших реквизитов.