TypeScript自定义接口变量声明

3

我是一名TypeScript初学者,目前正在TutorialsPoint上学习这门语言。我现在很难理解以下两段代码的区别。

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

这两者有什么区别?是否有特定情况下使用第一/第二种实现更好的要求?

谢谢。


https://basarat.gitbooks.io/typescript/docs/tips/lazyObjectLiteralInitialization.html - jcalz
2个回答

7
他们最终意义相同,但前者更可取。在这种情况下:
var drummer: Musician = {
    instrument: "drum",
    age: 28
}

您正在使用类型注释声明drummer是一个Musician,并将对象文字分配给它。编译器很高兴做到这一点,因为它可以验证您分配的对象文字是否与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 属性。您正在收到有关此警告。现在, 知道下面两行代码将解决这个问题,但编译器不知道。
因此,您可以将其更改为使用类型断言而不是类型注释:
var drummer = <Musician>{}; // okay
drummer.instrument = "drum"
drummer.age = 28

断言是告诉编译器 "这个对象确实是一个音乐家,尽管现在看起来不像"。您需要承担确保 drummer 是一个 Musician 的责任,并解除编译器验证的责任。

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

前者更可取,因为通常情况下希望编译器能够验证类型。类型断言会降低一些安全性,这没关系,直到发生问题就像没有戴安全带驾驶汽车一样。
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。因此,需要使用断言。
理解了吗?希望能帮到你,祝好运!

0
例子略有不同:
- 在第一个例子中,您正在定义具有类型Musician的变量,然后将符合该类型的对象分配给该变量。 - 在第二个例子中,您正在定义一个没有显式类型的变量(这意味着TypeScript会推断它),创建一个空对象,然后将该对象强制转换为类型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;

这将使得情况更加清晰(对于您、其他开发人员和编译器),即那些字段可能未定义的情况。


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