【问题标题】:How to fix the Error "Type 'unknown[]' is not assignable to type 'Product[]'"如何修复错误“类型'unknown []'不可分配给类型'Product []'”
【发布时间】:2020-06-24 07:58:44
【问题描述】:

在我使用最新版本时遵循 Angular 4 制作的课程,但我终生无法解决这个问题。 尝试过滤产品时,products.component.ts 出现错误。

任何帮助将不胜感激,我还是新手,这是我学习 Angular 的第四天。

Type 'unknown[]' is not assignable to type 'Product[]'. 
Type '{}' is missing the following properties from type 'Product': title, price, category, imageUrl

product.ts

export interface Product {
    title: string;
    price: number;
    category: string;
    imageUrl: string;
}

product.service.ts

import { map } from 'rxjs/operators';
import { AngularFireDatabase } from 'angularfire2/database';
import { Injectable } from '@angular/core';
import { Product } from './models/product';

@Injectable({
  providedIn: 'root'
})
export class ProductService {

  constructor(private db: AngularFireDatabase) { }

  create(product) {
    return this.db.list('/products').push(product);
  }



  getAll(){
    return this.db.list('/products').snapshotChanges()
      .pipe(
        map(actions =>
          actions.map(a => ({ key: a.key, ...a.payload.val() }))
        )
      );
  }

  get(productId) {
    return this.db.object('/products/' + productId);
  }

  update(productId, product) {
    return this.db.object('/products/' + productId).update(product);
  }

  delete(productId)
  {
    return this.db.object('/products/' + productId).remove();
  }

}

products.component.ts

import { ActivatedRoute } from '@angular/router';
import { CategoryService } from './../category.service';
import { ProductService } from './../product.service';
import { Component, OnInit } from '@angular/core';
import { Product } from '../models/product';
import { Observable } from 'rxjs';

@Component({
  selector: 'app-products',
  templateUrl: './products.component.html',
  styleUrls: ['./products.component.css']
})
export class ProductsComponent {
  products: Product[];
  categories$: Observable<any[]>;
  category: string;
  filteredProducts: Product[];

  constructor(

    productService: ProductService, 
    categoryService: CategoryService,
    route : ActivatedRoute) {

    productService.getAll().subscribe(a => this.products = a); //error on this.products: 

    //"Type 'unknown[]' is not assignable to type 'Product[]'."
    //  "Type '{}' is missing the following properties from type 'Product': title, price, category, imageUrl"

    this.categories$ = categoryService.getAll();

    route.queryParamMap.subscribe(params => {

      this.category = params.get('category');

      this.filteredProducts = (this.category) ?
      this.products.filter(p => p.category === this.category) : this.products;

    });
   }  
}

【问题讨论】:

    标签: angular typescript


    【解决方案1】:

    我相信这是因为您没有指定将使用 getAll() 方法检索的数据类型。

    TypeScript 是一种强类型语言,因此它会尝试在编译时验证所有类型和赋值。

    尝试使用以下命令更改不稳定的行:

    productService.getAll().subscribe((a: Product[]) => this.products = a);
    

    【讨论】:

    • 感谢您的回答,但这不起作用。我想我会放弃这门课程,并寻找能教我 Angular8 而不是 4 的东西。除了成为这个菜鸟之外,我还必须花几个小时阅读文档和 stackoverflow 来解决小问题:X跨度>
    【解决方案2】:

    AFAIK list 是通用的,您可以而且应该提供打字。而不是

        return this.db.list('/products').snapshotChanges()
    

        return this.db.list<Product>('/products').snapshotChanges()
    

    https://github.com/angular/angularfire2/blob/master/docs/rtdb/lists.md

    【讨论】:

      【解决方案3】:

      问题在于这个 observable -

      getAll(){
          return this.db.list('/products').snapshotChanges()
            .pipe(
              map(actions =>
                actions.map(a => ({ key: a.key, ...a.payload.val() }))
              )
            );
        }
      

      您正在将您的操作数组映射到一个数组。 当您期待一个数组时(即 Product[])。

      因此确保将操作数组映射到产品数组(即数组) 尝试像这样更改您的代码 -

      getAll(){
              return this.db.list('/products').snapshotChanges()
                .pipe(
                  map(actions =>
                    actions.map(a => {
                       title: <fill this from equivalent in a>,
                       price: <fill this from equivalent in a>,
                       category: <fill this from equivalent in a>,
                       imageUrl: <fill this from equivalent in a>
                    })
                  )
                );
            }
      

      顺便说一句,问题不在于 Angular 4 和 Angular 8 [同样的例子在 Angular8 中也会给出同样的错误]。这就是 Typescript 类型检查的工作原理。如果您使用普通的 javascript 编写相同的代码,那么您可能在编译时看不到任何错误,但您会在运行时看到意外行为。这里 typescript 确保尽可能在编译时捕获错误。

      【讨论】:

        【解决方案4】:

        product.ts

        export interface Product {
            key: string;
            title: string;
            price: number;
            category: string;
            imageUrl: string;
        }
        

        products.component.ts

        import { ProductService } from './../../product.service';
        import { Component, OnInit, OnDestroy } from '@angular/core';
        import { Subscription } from 'rxjs';
        import { Product } from 'src/app/models/product';
        
        @Component({
            selector: 'app-admin-products',
            templateUrl: './admin-products.component.html',
            styleUrls: [ './admin-products.component.css' ]
        })
        export class AdminProductsComponent implements OnInit, OnDestroy {
            products: Product[];
            filteredProducts: Product[];
            subscription: Subscription;
            constructor(private productservice: ProductService) {
                this.subscription = this.productservice
                .getAll()
                .subscribe((products: Product[]) => (this.filteredProducts = this.products = products));
            }
        
            filter(query: string) {
                this.filteredProducts = query
                ? this.products.filter((p) => p.title.toLowerCase().includes(query.toLowerCase()))
                : this.products;
            }
        
            ngOnDestroy() {
                this.subscription.unsubscribe();
            }
        
            ngOnInit() {}
        }
        

        products.component.html

        <tr *ngFor="let p of filteredProducts">
            <td>{{ p.title }}</td>
            <td>{{ p.price }}</td>
            <td>
                <a [routerLink]="['/admin/admin-products/', p.key]">Edit</a>
            </td>
        </tr>
        

        【讨论】:

        • 如果你能在你的答案中添加一些描述会很棒。
        【解决方案5】:

        这会改变你的生活。

        getAll() {
            return this.db.list<Product>('/products').snapshotChanges()
              .pipe(
                map(actions =>
                  actions.map(a => ({ key: a.key, ...a.payload.val() }))
                )
              );
        }
        

        【讨论】:

        • 您能解释一下解决方案吗?它有什么作用?与问题中的代码相比有何不同?
        猜你喜欢
        • 2020-07-29
        • 1970-01-01
        • 2019-12-01
        • 2020-07-28
        • 2021-10-28
        • 2020-07-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多