如何解决错误“类型'unknown []'无法分配给类型'产品[]'”的问题

时间:2019-06-07 00:56:30

标签: angular typescript

在我使用最新版本的同时,按照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;

    });
   }  
}

5 个答案:

答案 0 :(得分:0)

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

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

尝试使用以下方法更改不稳定线:

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

答案 1 :(得分:0)

问题在于这个可观察的-

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

您正在将动作数组映射到Array <{key,[]}>。 当您期望一个数组(即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编写相同的代码,则可能在编译时没有看到任何错误,但在运行时会看到意外的行为。这里的打字稿可以确保在编译时尽可能地捕获错误。

答案 2 :(得分:0)

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>

答案 3 :(得分:0)

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

答案 4 :(得分:0)

这可以改变你的生活。

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