React 和 Typescript,Axios 响应的类型都有哪些?

Posted

技术标签:

【中文标题】React 和 Typescript,Axios 响应的类型都有哪些?【英文标题】:React and Typescript, which types for Axios response?React 和 Typescript,Axios 响应的类型有哪些? 【发布时间】:2020-09-24 19:06:22 【问题描述】:

我正在尝试从返回以下内容的 API 中呈现一个简单的用户列表:

["UserID":2,"FirstName":"User2","UserID":1,"FirstName":"User1"]

我不完全了解如何处理带有类型的 Axios 响应。打字稿错误是

Type ' |  id: number; firstName: string; ' is not assignable to type 'IntrinsicAttributes & UserListProps &  children?: ReactNode; '.
Property 'items' is missing in type '' but required in type 'UserListProps'.

来自下面Users.tsx 文件中的<UserList /> 元素。我的User接口错了吗?

import React, useEffect, useState, Fragment  from 'react';
import UserList from './UserList';
import axios, AxiosResponse from 'axios';

interface User 
    id: number;
    firstName: string;


const Users: React.FC = (props) => 
    const [users, setUserList] = useState<User>();

    useEffect(() => 
        // Use [] as second argument in useEffect for not rendering each time
        axios.get('http://localhost:8080/admin/users')
        .then((response: AxiosResponse) => 
            console.log(response.data);
            setUserList( response.data );
        );
    , []);

    return (
        <Fragment>
            <UserList ...users />
        </Fragment>

    );
;
export default Users;

下面是我的UserList.tsx

import React, Fragment  from 'react';

interface UserListProps 
    items: id: number, firstName: string[];
;

const UserList: React.FC<UserListProps> = (props) => 
    return (
        <Fragment>
            <ul>
            props.items.map(user => (
                <li key=user.id>
                    <span>user.firstName</span>
                    /* not call delete function, just point to it
                    // set this to null in bind() */
                </li>
            ))
            </ul>
        </Fragment>
    );
;

export default UserList;

【问题讨论】:

【参考方案1】:

有generic get method defined in axios/index.d.ts

get<T = never, R = AxiosResponse<T>>(url: string, config?: AxiosRequestConfig<T>): Promise<R>;

例子

interface User 
    id: number;
    firstName: string;



axios.get<User[]>('http://localhost:8080/admin/users')
        .then(response => 
            console.log(response.data);
            setUserList( response.data );
        );

--编辑

我认为您将列表以错误的方式传递给子组件。

const [users, setUserList] = useState<User[]>([]);
<UserList items=users />
interface UserListProps 
    items: User[];
;
const UserList: React.FC<UserListProps> = (items) => 
    return (
        <Fragment>
            <ul>
            items.map(user => (
                <li key=user.id>
                    <span>user.firstName</span>
                </li>
            ))
            </ul>
        </Fragment>
    );
;

【讨论】:

谢谢,所以我应该使用axios.get&lt;User&gt; 而不是useState&lt;User&gt;()?如果我尝试这样做,Typescript 会抱怨 useState() 未定义。 更新了答案。起初我以为你只是得到一个对象,但这实际上是一个数组。只需将[] 括号放在几个地方 我认为现在唯一缺少的部分是我如何初始化useState()。我明白了:Argument of type 'User[]' is not assignable to parameter of type 'SetStateAction&lt;undefined&gt;'. Type 'User[]' provides no match for the signature '(prevState: undefined): undefined'.ts(2345) 你必须用空数组初始化useState([])。否则,您必须扩展类型 useState&lt;User[] | undefined&gt;() 添加检查变量是否在子组件中未定义并对其进行处理【参考方案2】:

如果您不希望 axios 推断值 response 的类型,则需要在调用 axios.get 时提供类型参数。

当您useState 创建用户数组时,您传递的类型参数不正确。

正确的方法

interface User 
  id: number;
  firstName: string;


// initialized as an empty array
const [users, setUserList] = useState<User[]>([]); // users will be an array of users

例如,

import React, useEffect, useState, Fragment  from 'react';
import UserList from './UserList';
import axios from 'axios';

interface User 
  id: number;
  firstName: string;


// you can export the type TUserList to use as -
// props type in your `UserList` component
export type TUserList = User[]

const Users: React.FC = (props) => 
   // you can also use User[] as type argument
    const [users, setUserList] = useState<TUserList>();

    useEffect(() => 
        // Use [] as second argument in useEffect for not rendering each time
        axios.get<TUserList>('http://localhost:8080/admin/users')
        .then((response) => 
            console.log(response.data);
            setUserList( response.data );
        );
    , []);

    return (
        <Fragment>
            <UserList ...users />
        </Fragment>

    );
;
export default Users;

如果您选择导出类型type TUserList = User[],您可以在UserList 组件中使用它作为道具类型。例如,

import React, Fragment  from 'react';
import  TUserList  from './Users';

interface UserListProps 
    items: TUserList // don't have to redeclare the object again
;

const UserList: React.FC<UserListProps> = (props) => 
    return (
        <Fragment>
            <ul>
            props.items.map(user => (
                <li key=user.id>
                    <span>user.firstName</span>
                    /* not call delete function, just point to it
                    // set this to null in bind() */
                </li>
            ))
            </ul>
        </Fragment>
    );
;

export default UserList;

【讨论】:

关于导出TUserList 类型非常好,非常感谢您的出色回答:) 我很高兴它有帮助。

以上是关于React 和 Typescript,Axios 响应的类型都有哪些?的主要内容,如果未能解决你的问题,请参考以下文章

React-query 和 Typescript - 如何正确输入突变结果?

使用 Typescript 创建 React 组件

TypeScript && React

react: typescript system params method optimize

如何测试使用自定义 TypeScript React Hook 的组件?

如何测试使用自定义TypeScript React Hook的组件?