【问题标题】:React/Typscript: typehint any doesn't workReact/Typescript:类型提示任何都不起作用
【发布时间】:2020-02-17 15:30:17
【问题描述】:

我有一个非常简单的 react 组件,名为:github.tsx

在里面,我有这个代码:

import React from 'react'
import axios from 'axios'

class Github extends React.Component<{any, any}>{

  state = {
    user: []
  }

  getRepoUser = async () => {
    let res = await axios.get('https://api.github.com/users/example');
    this.setState({
      user: res.data
    })
  }

  componentDidMount () {
   this.getRepoUser()
  }

  render () {
    const { user } = this.state

    return (
      <div>
        <h2>{user.login}</h2>
        <p> repos: {user.public_repos} </p>
        <p>followers: {user.followers}</p>
        <img src={user.avatar_url} alt=""/>
      </div>
    )
  }
}

export default Github

我认为通过将&lt;{any, any}&gt; 添加到组件中,我不会有任何问题,但我看到这样的控制台错误:

backend.js:6 /home/example/tuts/components/github.tsx
./components/github.tsx
[tsl] ERROR in /home/example/tuts/components/github.tsx(35,24)
      TS2339: Property 'avatar_url' does not exist on type 'any[]'.

对于user.loginuser.public_reposuser.followersuser.avatar_url,我收到上述错误 4 次

【问题讨论】:

    标签: reactjs typescript jsx typescript-generics


    【解决方案1】:

    当你创建一个组件时,你传递给React.Component的第一个类型是props类型,而第二个定义了状态类型:

    interface IState {}
    
    interface IProps {}
    
    class Component extends React.Component<IProps, IState> {
    

    当你这样做时:

    class Github extends React.Component<{any, any}>
    

    您只是将组件 props 类型定义为一个对象,该对象具有两个名为 any 的属性,这不起作用。

    您的组件类型需要改为:

    class Github extends React.Component<any, any>
    

    state.user 的推断类型也是一个数组,因为初始状态是:

    state = {
      user: []
    }
    

    这就是为什么您会收到有关 user.loginuser.public_repos 的错误...

    你可以这样输入状态:

    interface IState {
      user: User;
    }
    
    interface User {
      login: string;
      public_repos: string;
      followers: string;
      avatar_url: string;
    }
    
    class Github extends React.Component<any, IState> {
      public state = {
        user: {
          login: "",
          public_repos: "",
          followers: "",
          avatar_url: "",
        },
      };
    
      public getRepoUser = async () => {
        const res = await axios.get<User>("https://api.github.com/users/example");
        this.setState({
          user: res.data,
        });
      }
      ...
    }
    

    【讨论】:

    • 有趣!但是如果user 应该包含一个数组,我在类型提示中声明什么?我是否只需将第二个提示从any 更改为array&lt;any, array&gt;
    • 据我所知,user 是一个对象,而不是一个数组
    • 谢谢兄弟,在我接受你的回答之前,如果你不介意的话,我只有一个问题。为什么创建interface IState { user: User; } 而不是使用interface User {...} 并将其作为&lt;any, User&gt; 传递给组件,axios.get&lt;User&gt; 是做什么的?非常感谢
    • 因为你的状态是一个对象,它有一个名为user 的属性,其中包含用户信息——如果你这样做&lt;any, User&gt;,那么你的状态应该直接包含用户信息(state = {login: .., followers: ..})。 .
    • axios.get&lt;User&gt; 这只是为了输入res.data
    【解决方案2】:

    你犯了一个语义错误。虽然您的程序在语法上是有效的,但这并不意味着您的意图。

    关键点是,在 TypeScript 中,声明的形式是

    <name> [: type]
    

    也就是说,名称在前,并且始终是必需的,如果需要,可以在后面加上类型注释。

    因此,如果我写,

    type Props = {
        any
    };
    

    我正在声明一个具有名为any属性 的类型。以上等价于

    type Props = {
        any: any
    };
    

    因为我没有类型注释,也没有上下文可以推断它。

    另外,我写,

    type Props = {
        any,
        any
    };
    

    我有一个名为any 的成员被声明了两次,一个错误。

    您可能打算像这样为 PropsState 类型参数指定类型 any

    class Github extends React.Component<any, any> {
    
    }
    

    但是您却为Props 指定了{any, any} 的类型,而没有为State 指定类型。

    【讨论】:

    • 谢谢,如果用户是数组,我会传递什么状态?
    • {user: UserType[]}
    【解决方案3】:

    有多种原因:

    1. React.Component 接口接受两种类型,React.Component&lt;P, S&gt; 其中 P 是道具类型,S 是状态类型。它也可以接受一个类型,它只是 P。这就是你的情况,你将类型 P 定义为对象 {any, any} (打字稿应该抱怨它,因为你指定了重复的键)。这意味着您根本没有为 State 提供类型。来自DefinetelyTyped should be any

    2. 你在类上明确定义state,所以打字稿从定义中推迟了它的类型。 state.user 是一个数组,因此该元素上没有 avatar_url

    要解决此问题,您可以尝试在定义时明确说明 state 是 any

        state: any = {
            user: []
        }
    

    更好的解决方案是为状态实际定义一个类型或接口而不使用任何类型或接口。应避免使用any,尤其是在您为应用程序编写的代码中。

    您可以定义用户喜欢的类型或接口:

    type User = {
        name: string,
        avatar?: string
    }
    // or 
    interface IUser {
        name: string,
        avatar?: string
    }
    

    【讨论】:

    • 谢谢,但是我应该如何定义user 是否有多个键,例如name avatar?我可以做Interface User: {name: string, avatar: string} 并通过User 喜欢.. &lt;P, User} 吗?
    【解决方案4】:

    React.Component&lt;{any, any}&gt; 中的“Typehint”与 state 类型无关,这是你指定的 props 类型。查看 react 组件的声明:declare class React$Component&lt;Props, State = void&gt; { ...

    【讨论】:

    • 当你用一个空数组初始化状态时,你也会误导编译器,从而使它将状态的类型视为any[]
    • 我希望您提供更多信息,我现在比以前更困惑。你能给我一个解释这个的链接吗?
    • 嗯,我的意思是状态的类型被计算为{user: any[]}。您可以按照上面的建议明确提供它。另外请记住,当您在空数组上调用这些属性(登录名、关注者等)时,您可能会遇到运行时错误,因此您应该在那里进行一些检查。
    • 事实上,最好用空对象user: {}初始化用户,这样就可以了
    猜你喜欢
    • 2013-07-21
    • 2018-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-07
    • 1970-01-01
    • 2021-07-11
    • 2018-10-02
    相关资源
    最近更新 更多