类型“{}”不能赋值给类型“{title: string; text: string;}”。

26

下面是 TypeScript 代码的错误信息:

Type '{}' is not assignable to type '{ title: string; text: string; }'. Property 'title' is missing in type '{}'.

因为我像下面这样声明了“article”,

article: { title: string, text: string } = {};

这是什么原因,如何解决?谢谢!

import { Component } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';

@Component({
    selector: 'article-editor',
    template: `
    <p>Title: <input [formControl]="titleControl"></p>
    <p>Text: <input [formControl]="textControl"></p>
    <p><button (click)="saveArticle()">Save</button></p>
    <hr />
    <p>Preview:</p>
    <div style="border:1px solid #999;margin:50px;">
      <h1>{{article.title}}</h1>
      <p>{{article.text}}</p>
    </div>
  `
})
export class ArticleEditorComponent {
    article: { title: string, text: string } = {};

    titleControl: FormControl = new FormControl(null, Validators.required);
    textControl: FormControl = new FormControl(null, Validators.required);
    articleFormGroup: FormGroup = new FormGroup({
        title: this.titleControl,
        text: this.textControl
    });

    saveArticle() {
        if (this.articleFormGroup.valid) {
            this.article = this.articleFormGroup.value;
        } else {
            console.log('Missing field(s)!');
        }
    }
}

4个回答

43

你告诉编译器article是类型为{ title: string, text: string }的,但你却赋值了一个没有titletext的空对象({}),所以编译器会报错。

你可以使用类型断言来告诉编译器这样做是可以的:

let article: { title: string, text: string } = {} as { title: string, text: string };

你也可以将它放入类型别名中:

type MyType = { title: string, text: string };
let article: MyType = {} as MyType;

如果你正在使用类型断言,那么你可以简单地做到:

let article = {} as MyType;

2
这样做是完全错误的。在这种情况下,最好按照另一个答案中建议的方式将字段定义为可选的。 - Vilmantas Baranauskas
1
@VilmantasBaranauskas 这并不是所有情况下都是错误的。有时候你确实想要强制属性,但你只是暂时不设置它们。这样你就可以创建对象并分配属性。 - Nitzan Tomer
1
使用 as 运算符被认为是不好的形式。除非绝对必要,请不要使用它。它会破坏类型的信任。 - Mads Buch
2
已经过了很长时间,但是对于未来使用“as”的任何人而言,这仍然不是理想的选择。您会失去类型安全,并且可能在属性定义之前访问该属性,这完全是错误的事情。更好的方法是使用部分类型,然后在代码中属性被定义后再使用“as”。 - jeffkmeng

8
原因很简单,你声称 article 应该有 titletext 字段,但 {} 没有这些字段。如何解决取决于您在 article 具有初始值时想要显示什么内容,但最简单的解决方法是将这些字段设为可选:{ title?: string, text?: string }

添加可选项可以缓解问题,但会引入更广泛的类型。这可能会在应用程序中产生更多的样板代码来处理未定义的情况。如果可能的话,请保持一个健全的核心,减少可选类型的数量并严格控制。 - Mads Buch

1

由于上面提到了解决方案,但并未写出,因此您可以执行以下操作:

article: { title?: string, text?: string } = {};

如果允许空对象,则属性是可选的。如果您计划对象始终包含这些属性,并且只想定义结构,则只需声明它:
article: { title: string, text: string };

在你的代码中,没有任何情况会在对象的值被定义之前使用它。

0

我在这里为路过的人添加第三个选项:添加合理的默认值。

const article: { title: string, text: string } = {
    title: "default title",
    text: "default text"
};

这可能不适用于此处,但通常认为初始化对象以满足其类型并尽可能具有紧密类型是良好的编程习惯。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接