Typescript 自定义接口变量声明

Typescript custom interface variable declaration

这里是 TypeScript 新手,我目前正在 TutorialsPoint here 上学习这门语言。 我目前很难理解这两段代码之间的区别。

interface Person{
    age: number;
}

interface Musician extends Person{
    instrument: string;
}

var drummer:Musician = {
    instrument: "drum",
    age: 28
}

interface Person{
    age: number;
}

interface Musician extends Person{
    instrument: string;
}

var drummer = <Musician>{}
drummer.instrument = "drum"
drummer.age = 28

两者有什么区别?是否存在使用 first/second 实现更好的特定情况?

谢谢。

示例略有不同:

  • 首先,您要定义类型为 Musician 的变量,然后将对象分配给适合该类型的变量。
  • 第二,你定义了一个没有显式类型的变量(这意味着 TypeScript 会推断它),创建一个空对象,然后 casting 该对象以键入Musicican
    • 顺便说一句,在 TypeScript 中进行转换的首选语法是 {} as Musician - 您使用的尖括号语法与 React 应用程序常用的 JSX 语法扩展不兼容,因此它被替换了有一些不那么模棱两可的东西。

在绝大多数情况下,我会推荐第一个示例而不是第二个示例 - 空对象并没有真正实现 Musician,因此您实际上是在回避类型检查器!

您可以使用第二种方法的一种情况是,如果您有一个 Musician 一开始是空的,后来又被填充了——不过在那种情况下,我认为您会通过将字段设为可选,通过类型定义本身进行建模会更好:

interface Person {
    // '?' makes a field optional 
    age?: number;
}

interface Musician extends Person {
    instrument?: string;
}

// The cast can now be replaced with a proper type
var drummer: Musician = {};
drummer.instrument = "drum";
drummer.age = 28;

这让(您、其他开发人员和编译器)更清楚地知道在某些情况下这些字段将是未定义的。

它们最终是一样的,但在可能的情况下首选前者。

在这种情况下:

var drummer: Musician = {
    instrument: "drum",
    age: 28
}

您通过使用 type annotation 并为其分配对象文字来声明 drummerMusician。编译器对此很满意,因为它可以验证是的,您分配的对象文字与 Musician 接口兼容。它有一个字符串值 instrument 属性 和一个数值 age 属性。

现在如果我们尝试这个会怎样:

var drummer: Musician = {};
//  ~~~~~~~ <-- error!
// Type '{}' is not assignable to type 'Musician'.
//  Property 'instrument' is missing in type '{}'.
drummer.instrument = "drum"
drummer.age = 28

将空对象文字赋值给声明为 Musician 的值会导致编译器错误。毕竟,空对象字面量没有字符串值 instrument 属性 或数值 age 属性。你被警告了。现在, 知道接下来的两行将解决该问题,但编译器不会。

因此您可以将其更改为使用 type assertion 而不是类型注释:

var drummer = <Musician>{}; // okay
drummer.instrument = "drum"
drummer.age = 28

断言是您告诉编译器的地方 "this object is really a Musician, even though right now it doesn't look like it." 您负责确保 drummerMusician 并减轻编译器验证的责任给你。

并且由于接下来的两行添加了所需的属性,所以一切都很好。


前者更可取,因为您通常希望编译器在可能的情况下验证您的类型。类型断言放弃了一些安全性,这很好,直到它不是,就像驾驶没有安全带的汽车:

var drummer = <Musician>{}; // okay
drummer.age = 28;
// whoops, forgot the instrument, but TypeScript isn't complaining

// ... later ...
console.log(drummer.instrument.toUpperCase()); 
// no error at compile time
// but blows up at runtime

有时您必须使用类型断言。例如,当您有某种循环引用需要分段构建对象时:

interface MarriedPerson extends Person {
  spouse: MarriedPerson
}

var adam: MarriedPerson = {
  age: 0,
  // spouse: eve <-- can't do this before eve is defined
} as MarriedPerson;

var eve: MarriedPerson = {
  age: 0,
  spouse: adam
}

adam.spouse = eve;  // okay now

在上面,每个 MarriedPerson 都需要对 MarriedPerson... 的引用,但是在您创建一个之前不会有一个。因此,您不得不求助于 MarriedPerson 对象之一没有所需 spouse 的短时间。因此需要断言。

这有意义吗?希望能帮助到你;祝你好运!