首页 > 解决方案 > 错误 TS2339:“任何 []”类型上不存在属性“名称”

问题描述

我在 Angular 文档和 stackoverflow 上进行了搜索,但没有什么像我的问题。我可能不明白一些事情。但我的问题如下:

角 CLI:11.0.2 节点:14.15.1

我的服务:

export class ApiService {

  constructor(private httpClient: HttpClient) { }

  /**
   * Get teams by id
   * @param id 
   * @returns 
   */
   getTeamFromServe(id: number){
    return this.httpClient.get('https://api.football-data.org/v2/teams/'+ id, {
      headers: {
        'X-Auth-Token': 'XXXXXXXXXXXXXXXXX'
      },
      observe: 'body',
      responseType: 'text'
    })
  }
} 

在我的组件中:

团队详细信息.components.js :

@Component({
  selector: 'app-team-detail',
  templateUrl: './team-detail.component.html',
  styleUrls: ['./team-detail.component.scss']
})
export class TeamDetailComponent implements OnInit {

  arrayTeamInfo: Array<any> = [];

  constructor(private apiService: ApiService,
              private router: Router,
              private route: ActivatedRoute) { }

  ngOnInit(): void {
    const id = this.route.snapshot.params['id'];

    this.apiService.getTeamFromServe(id).subscribe(
      data => {
        let arrayData = [];
        arrayData = JSON.parse(data);
        this.arrayTeamInfo = arrayData;
        console.log(this.arrayTeamInfo);
      }, err => {
        this.arrayTeamInfo = JSON.parse(err.error).message;
      }
    )
  }
}

结果 consol.log :

activeCompetitions: []
address: "null Rio de Janeiro, RJ null"
area: {id: 2032, name: "Brazil"}
clubColors: "Red / Black / White"
crestUrl: "https://crests.football-data.org/1783.svg"
email: null
founded: 1919
id: 1783
lastUpdated: "2020-09-10T02:18:46Z"
name: "CR Flamengo"
phone: null
shortName: "Flamengo"
squad: []
tla: "FLA"
venue: "Estadio Jornalista Mário Filho"
website: "https://www.flamengo.com.br/pagina-inicial-basquete"

团队详细信息.component.html :

<h1> 
    {{ arrayTeamInfo.name }} 
</h1>

每个属性都会出现此问题,例如(地址、clubColors、电子邮件...)。我收到了这个错误: Error: src/app/teams/team-detail/team-detail.component.html:9:38 - error TS2339: Property 'name' does not exist on type 'any[]'.

但是,如果我在我的 html 文件上执行此操作,它就可以工作:

<h1> 
    {{ arrayTeamInfo['name']}} 
</h1>

我只是随机使用这种语法,我不明白为什么我必须在这里这样做,而在我创建的所有其他组件中(具有完全相同的结构)我没有问题......

我错过了一部分吗?

标签: angulartypescriptstring-interpolation

解决方案


在组件类中,您说:

arrayTeamInfo: Array<any> = []

所以arrayTeamInfo肯定会是一个数组;它的名称以“array”开头,它有一个数组类型(Array<any>与 相同any[]),默认值为错误。完全清楚。您在接收数据时加强了这一点:

let arrayData = [];
arrayData = JSON.parse(data);
this.arrayTeamInfo = arrayData;

空数组值未使用,但确实将arrayData("array" again!) 的类型设置为any[]. 这是 100% 的数组,当然不会不是数组。正确的?但是然后在模板中,您可以:

<h1> 
    {{ arrayTeamInfo.name }} 
</h1>

数组没有名称,因此当编译器对此进行类型检查时,自然会有些困惑。因此(完全准确的)错误:

Property 'name' does not exist on type 'any[]'.

在您的问题中,您向团队信息展示的不是一个数组,并说它arrayTeamInfo['name'] 确实有效,所以问题是:您为什么要花这么多时间说服编译器您的价值将是一个数组,如果它不是?


那么如何解决呢?首先,您应该在代码库的某处表达团队信息的实际形状:

interface Team {
  name: string;
  area: {id: number; name: string};
  /* ...other props */
}

然后,当您从服务器获取数据时,您实际上可以使用它,因此您的其余代码知道它应该期望接收什么 - 指定方法的返回类型,并使用泛型类型参数HttpClient#get(参见https:/ /angular.io/guide/http#requesting-a-typed-response):

export class ApiService {

  constructor(private httpClient: HttpClient) { }

  getTeamFromServe(id: number): Observable<Team> {
    return this.httpClient.get<Team>(  // <- set this
      `https://api.football-data.org/v2/teams/${id}`,
      { 
        headers: {'X-Auth-Token': 'XXXXXXXXXXXXXXXXX'},
        /* other options restated defaults or were wrong */
      }
    )
  }
} 

最后,在您的组件中,属性的类型实际上应该反映您计划分配给它的内容,因此编译器可以检查您编写的内容是否有意义:

@Component({
  selector: 'app-team-detail',
  templateUrl: './team-detail.component.html',
  styleUrls: ['./team-detail.component.scss']
})
export class TeamDetailComponent implements OnInit {

  teamInfo?: Team;  // <- no initial value, so undefined until request completes

  constructor(private apiService: ApiService,
              private router: Router,
              private route: ActivatedRoute) { }

  ngOnInit(): void {
    const id = this.route.snapshot.params['id'];

    this.apiService.getTeamFromServe(id).subscribe(data => {
      this.teamInfo = data;  // <- data is typed as Team, so the compiler's happy
    })
  }
}
<h1> 
    {{ teamInfo?.name }}
    <!-- safe navigation handles undefined default --> 
</h1>

(请注意,组件不再需要JSON.parse来自服务的数据 - 拥有单独服务的目的是从表示层抽象出传输层的细节,因此有类似“我们将数据作为 JSON string" 泄漏到组件中没有帮助。)

另一种选择是更倾向于使用可观察对象,使用| async管道而不是需要安全导航;几年前我在我的博客上写过这个(使用旧Http语法,但这些想法仍然有用)。


推荐阅读