TypeScript类型报错求助:{}[]无法赋值给ShoppingCartItem[]
我懂你这种纠结——编译时明明飘着类型错误提示,可程序居然还能正常跑,但这个红标看着实在闹心对吧?咱们来把这个问题彻底理顺解决掉。
报错原因拆解
先看你收到的具体报错:
Type '{}[]' is not assignable to type 'ShoppingCartItem[]'. Type '{}' is not assignable to type 'ShoppingCartItem'. Property 'product' is missing in type '{}'.
核心问题在于:Firebase的valueChanges()方法默认返回的是未指定类型的对象数组(TypeScript把它识别成{}[]),而你的ShoppingCarts构造函数需要的是严格符合ShoppingCartItem[]类型的数组。TypeScript没办法自动推断从数据库拿回来的这些对象刚好拥有product和quantity属性,所以就抛出了类型不匹配的错误。
至于程序能运行,是因为JavaScript本身是弱类型语言,它不管这些编译时的类型约束,只要运行时对象有对应的属性就能正常工作,但TypeScript的报错是在帮你提前规避潜在的类型风险,所以咱们得把这个类型缺口补上。
解决方案
这里给你两种靠谱的修改方式,选哪种都能解决问题:
方案1:给Firebase Collection指定泛型类型
直接在collection()方法里明确指定它返回的是ShoppingCartItem类型的数据,让TypeScript提前知晓数据结构:
async getCart(): Promise<Observable<ShoppingCarts>> { let cartId = await localStorage.getItem('cartId'); // 给collection指定ShoppingCartItem泛型,valueChanges就会返回Observable<ShoppingCartItem[]> return this.shoppingCartCollection.doc(cartId).collection<ShoppingCartItem>('items').valueChanges() .map(data => new ShoppingCarts(data)); }
方案2:用类型断言明确数据类型
如果因为某些原因没法给Collection指定泛型,也可以在映射数据的时候用类型断言,直接告诉编译器“这些数据就是ShoppingCartItem[]类型”:
async getCart(): Promise<Observable<ShoppingCarts>> { let cartId = await localStorage.getItem('cartId'); return this.shoppingCartCollection.doc(cartId).collection('items').valueChanges() // 断言data为ShoppingCartItem[]类型 .map(data => new ShoppingCarts(data as ShoppingCartItem[])); }
额外优化建议
另外,你的ShoppingCarts类可以做个小优化,用ShoppingCartItem[]代替Array<ShoppingCartItem>(这是TypeScript更常用的写法,可读性更好),同时把统计总数量的逻辑换成更简洁的reduce写法:
export class ShoppingCarts{ constructor(public shoppingItems: ShoppingCartItem[]){} get getProducts(){ return this.shoppingItems.filter(element => element.quantity !== 0); } get totalItemsCount(){ return this.shoppingItems.reduce((total, item) => total + item.quantity, 0); } }
这样修改之后,TypeScript就不会再报那个类型不匹配的错误了,同时代码的类型安全性和简洁性也能得到提升。
内容的提问来源于stack exchange,提问作者vamlumber

