Angular项目ng build --prod报属性不存在错误,ng serve正常
解决Angular生产构建时"Property does not exist on type '{}'"的问题
嘿,我明白你现在的困境——开发环境跑的好好的,一到生产构建就炸一堆类型错误,还没法部署。这个问题其实是Angular生产模式下的严格类型检查在搞事情,咱们一步步来搞定它:
问题根源分析
你初始化recipe = {}的时候,TypeScript会自动把它的类型推断成{}(空对象)。生产构建时,TypeScript会开启严格模式,它会较真:空对象上根本没有title、source这些属性啊!所以就抛出了那些错误。但如果你只写recipe;,它的类型会变成undefined或者any,当数据库数据还没加载完时,模板访问recipe.title就会因为recipe是undefined而报错,导致下拉框空白、控制台一堆问题。
完美解决方案:给Recipe定义类型并合理初始化
咱们需要给recipe一个明确的类型,同时初始化必要的属性,两边的问题就都解决了:
- 先定义Recipe接口
在组件文件顶部,添加一个接口来描述你的recipe对象结构,用可选属性(?)允许属性初始为空:
interface Recipe { title?: string; source?: string; category?: string; ingredientsList?: { ingredients: string[] }; directions?: string; // 这里可以补充你的recipe对象需要的其他属性 }
- 修改recipe的声明和初始化
把原来的recipe = {};改成下面这样,既指定类型,又初始化ingredientsList避免模板访问时的undefined错误:
recipe: Recipe = { ingredientsList: { ingredients: [] } };
- 修改后的完整组件代码
import { RecipeService } from './../recipe.service'; import { Observable } from 'rxjs/Observable'; import { CategoryService } from './../category.service'; import { Component } from '@angular/core'; import { AngularFireObject, AngularFireDatabase, AngularFireList } from 'angularfire2/database'; import { FirebaseListObservable } from "angularfire2/database-deprecated"; import { FormGroup, FormControl, FormArray } from '@angular/forms'; import { FirebaseApp } from 'angularfire2'; import { Router, ActivatedRoute } from '@angular/router'; import 'rxjs/add/operator/take'; // 定义Recipe接口,明确对象结构 interface Recipe { title?: string; source?: string; category?: string; ingredientsList?: { ingredients: string[] }; directions?: string; } @Component({ selector: 'app-recipe-form', templateUrl: './recipe-form.component.html', styleUrls: ['./recipe-form.component.css'] }) export class RecipeFormComponent { categories$: Observable<any>; // 用接口类型声明,并初始化必要属性 recipe: Recipe = { ingredientsList: { ingredients: [] } }; id; form = new FormGroup({ ingredients: new FormArray([]) }); constructor( private categoryService: CategoryService, private recipeService: RecipeService, private router: Router, private route: ActivatedRoute) { this.categories$ = categoryService.getCategories(); this.id = this.route.snapshot.paramMap.get('id'); if(this.id) this.recipeService.get(this.id).take(1).subscribe(r => this.recipe = r); } save(recipe){ recipe.ingredientsList = this.form.value; if(this.id) this.recipeService.update(this.id, recipe); else this.recipeService.create(recipe); this.router.navigate(['/recipes']); } addIngredient(ingredient: HTMLInputElement) { this.ingredients.push(new FormControl(ingredient.value)); ingredient.value = ''; } getList(){ return this.form.get('ingredients') as FormArray; } get ingredients() { return this.form.get('ingredients') as FormArray; } removeIngredient(ingredient: FormControl){ let index = this.ingredients.controls.indexOf(ingredient); this.ingredients.removeAt(index); } }
为什么这能解决问题?
- 类型安全:有了
Recipe接口,TypeScript清楚知道recipe可以拥有哪些属性,生产构建的严格检查就不会再挑刺了。 - 避免初始化错误:提前给
ingredientsList赋值空数组结构,就算数据库数据还没加载完成,模板访问recipe.ingredientsList.ingredients时也不会因为undefined报错,下拉框和表单就能正常显示了。
另外,你的模板里这段代码:
<div *ngIf="recipe.ingredientsList"> <ul class="list-group"> <li *ngFor="let i of recipe.ingredientsList.ingredients" (click)="removeIngredient(i)" class="list-group-item"> {{ i }} </li> </ul> </div>
因为我们已经初始化了ingredientsList,*ngIf="recipe.ingredientsList"其实可以去掉,但保留也没问题,多一层安全保障。
现在再跑ng build --prod应该就能顺利完成构建啦!
内容的提问来源于stack exchange,提问作者MortiMonster28
相关产品推荐
相关产品推荐

