В типе React ts ‘Promise’ отсутствуют следующие свойства из типа ‘X’

#reactjs #typescript #axios

#reactjs #машинописный текст #аксиос

Вопрос:

Я пытаюсь переместить свой запрос API в отдельную службу и столкнулся с этой проблемой.

Вот мой интерфейс

 export interface IProduct {
  id: any;
  productName: string;
  productDescription: string;
  productImage: string;
  productPrice: any;
  categoryId: string;
  category: any;
}
 

Вот компоненты для списка продуктов

 import React, {useEffect, useState} from 'react';

import {IProduct} from "../models"

interface IProps {
products: IProduct[];
}

export const ProductsList: React.FC<IProps> = ({products}) => {

  return (
    <div className="App">
      <ul className="posts">
        {products.map((products) => (
          <li key={products.id}>
            <h3>{products.productName}</h3>
            <p>{products.productDescription}</p>
            <h2>{products.productPrice}</h2>
          </li>
        ))}
      </ul>
    </div>
  );
}

export default ProductsList;
 

Далее Api.tsx , где я пытаюсь сделать запрос:

 import axios, { CancelTokenSource } from "axios";

import {IProduct} from "../models"
import React from 'react';

export const fetchAllProducts = async (setData: IProduct[]): Promise<IProduct[]> => {
  return axios.get<IProduct[]>("https://localhost:5001/api/ShowAllProducts")
    .then(response => {return setData = response.data });
}
 

и, наконец, APP.tsx

 import axios, { CancelTokenSource } from "axios";
import {IProduct} from "./models"
import {ProductsList} from "./components/ProductsList";
import React from 'react';
import {fetchAllProducts} from './services/api';

const defaultProps:IProduct[] = [];


function App() {
  const [products, setProducts] = React.useState<IProduct[]> 
    (defaultProps)

  const [loading, setLoading]: [boolean, (loading: boolean) => void] = React.useState<boolean>(true);
  const [error, setError]: [string, (error: string) => void] = React.useState("");

  return (
    <div>
      <ProductsList products= {fetchAllProducts(products)}/>
    </div>
  );
}

export default App;
 

Итак, у меня есть ошибка в app.tsx в return прямо перед символом «=» на продуктах.

В нем говорится:

 Type 'Promise<IProduct[]>' is missing the following properties from type 'IProduct[]': length, pop, push, concat, and 28 more.ts(2740)
ProductsList.tsx(6, 5): The expected type comes from property 'products' which is declared here on type 'IntrinsicAttributes amp; IProps amp; { children?: ReactNode; }'
 

Комментарии:

1. fetchAllProducts возвращает `Обещание<IProduct[]> . You're trying to pass that as a prop, which expects an IProduct[]`.

Ответ №1:

Мне кажется, что строка

 .then(response => {return setData = response.data });
 

должно быть переписано как:

 .then(response => Promise.resolve(response.data));
 

Это должно решить вашу проблему

Комментарии:

1. спасибо, я понял это, я думал, что второй аргумент в const[X, Y] — это просто var , но это функция, поэтому я изменил свои аргументы api, чтобы он мог принимать func .

Ответ №2:

Те свойства, которые в сообщении об ошибке указаны как отсутствующие, являются свойствами массива.

 interface IProps {
products: IProduct[];
}

export const ProductsList: React.FC<IProps> = ({products}) => {
...
}
 

В приведенном выше коде вы указываете ProductsList компоненту ожидать массив с именем products в качестве реквизита.

Но в APP.tsx в строке

 <ProductsList products= {fetchAllProducts(products)}/> 
 

вы отправляете fetchAllProducts(products) в качестве products реквизита. fetchAllProducts(products) это функция, которая возвращает обещание, а не массив.

Чтобы исправить это, вы могли бы написать что-то вроде:

   function App() {
    const [products, setProducts] = React.useState<IProduct[]> 
      (defaultProps)  
    const [loading, setLoading]: [boolean, (loading: boolean) => void] = React.useState<boolean>(true);
    const [error, setError]: [string, (error: string) => void] = React.useState("");

    React.useEffect(async () => {
      const allproducts = await fetchAllProducts();
      setProducts(allproducts)
      }, [])
  
    return (
      <div>
        <ProductsList products={products}/>
      </div>
    );
  }
 

Таким образом, вы извлекаете все продукты при App монтировании компонента и передаете массив в качестве products реквизита ProductsList .

Комментарии:

1. спасибо, я понял это, я думал, что второй аргумент в const[X, Y] — это просто var , но это функция, поэтому я изменил свои аргументы api, чтобы он мог принимать func .

Ответ №3:

Спасибо всем вам, ребята, я понял это, кстати, ваши ответы помогли мне понять одну вещь. я думал, что

 const [products, setProducts] = React.useState<IProduct[]>(defaultProps) 
 

похоже на typesriptish {set; get;} из .net lol.
но теперь я знаю, что второй аргумент — это функция. поэтому я просто изменил аргумент в своем файле api.tsx, чтобы он теперь принимал функции.

таким образом, компонент и интерфейс остаются без изменений

вот мой api.tsx

 export const fetchAllProducts = async (func: any): Promise<IProduct[]> => {
return axios.get<IProduct[]> ("https://localhost:5001/api/ShowAllProducts")
.then(response => {return func(response.data)});}
 

и вот APP.tsx

 const defaultProps:IProduct[] = [];

function App() {
const [products, setProducts] = React.useState<IProduct[]>(defaultProps) 
const [loading, setLoading]: [boolean, (loading: boolean) => void] = 
React.useState<boolean>(true);
const [error, setError]: [string, (error: string) => void] = 
React.useState("");

React.useEffect(() => {
async () => await fetchAllProducts(setProducts);
}, [])

 return (
<div>
  <ProductsList products={products}/>
</div>
);
}
export default App;