TypeScript:如何从对象初始化派生类



我有以下代码:

class MyClass {
name: string = "myname";
constructor(public action: string) { }
}
let obj1: MyClass = { action: "act1" };

它不可编译。最后一行的错误是:

Property 'name' is missing in type '{ action: string; }' but required in type 'MyClass'.

我本来以为,因为"name"属性有一个默认值,所以不应该为obj1指定它。但事实并非如此。此外,最后一行似乎甚至没有调用ctor,所以它不是一个ctor语法糖,而是一个完全不同的初始化调用。有没有一种方法可以设置某些属性的默认值,并避免在这种技术中初始化它们?

编写时:

let obj1: MyClass = { action: "act1" };

您使用类MyClass作为类型,这意味着您告诉编译器变量obj1符合MyClass类型。它必须具有类的所有必填字段,并且不能具有任何未知的属性。

这很好,因为如果类型有200个属性,intellisense可以提示您缺少属性。

现在,MyClass实际上是class,所以它不仅仅作为类型/接口工作。它还有一些功能,即您可以调用构造函数,并且在声明类时可以使用extends

现在,类的默认属性不是该类型的默认属性。如果您尝试在类型脚本interfacetype中添加初始值设定项,您将看到一个错误;相反,当您向类添加默认属性时,这意味着只有从构造函数调用时,实例才会将该属性初始化为默认值。

所以,你可以做一些事情来解决这个问题:

  1. 在该场景中,您可以继续使用MyClass作为类型,但仍需要在对象文字中声明name道具:

let obj1: MyClass = {action: "act1", name: "first"};

如果你这样做,你仍然会面临一个:

对象文字只能指定已知属性

因为action属性在MyClass中不存在。您需要将action属性添加到MyClass中。

  1. 使用构造函数

let obj1 = new MyClass("act1");

虽然在某些情况下,您可以有正当理由将类用作类型/接口,但您可能应该在可能的情况下调用类构造函数(如本例所示(,或者,正如注释所建议的那样,为此使用接口。

在这种情况下,我认为您应该更喜欢调用构造函数。

  1. 如果您只需要该类型来对变量类型进行编译器检查/intellisense,则可以使用接口:
interface MyCustomType {
name: string;
action?: string;
}

因此,如果您尝试将一个不带名称的变量键入为MyCustomType,则会收到警告:

let obj: MyCustomType = {
action: 'act1',
} // error, you need to set 'name' since it is a mandatory field

您可以设置有操作或无操作的对象,因为它是可选的(由于声明中的"?"(。

无法添加未知字段:

let obj: MyCustomType = {
name: 'name',
value: 1, // error, unknown field
}

在您的代码let obj1: MyClass = { action: "act1" };

您并没有将obj1初始化为MyClass的实例,而是将对象{ action: "act1" }分配给一个假定类型为MyClass的变量。因此出现了打字错误。

正确实施:

class MyClass {
name: string = "myname";
constructor(public action: string) { 
}
}
let obj1 = new MyClass("action");
console.log(obj1);
/* 
outputs:
{
action: "action"
name: "myname"
}
*/

感谢上面的所有建议,我终于想出了一个解决方案,让我使用ctor,但仍然会得到任何丢失/多余值的错误,并让我在对象文字"initializer"中设置可选的默认值:

class MyClassValues {
constructor(public name: string, public action?: string) {}
}
class MyClass extends MyClassValues {
constructor(v: MyClassValues) {
super(v.name, "default1");
}
}
let c1 : MyClass = new MyClass({}); // error, missing name
let c2 : MyClass = new MyClass({x:"y"}); // error, unknown prop
let c3 : MyClass = new MyClass({name:"hello"}); // no error
console.log(c3.action); // prints "default1";

最新更新