为什么 Typescript 接口有数据变量,而 Java 接口只能有常量?



来自Java,众所周知,接口是一个契约,因此只有方法签名和常量。尝试学习 Typescript,我很惊讶地看到接口定义中的数据变量请参阅Microsoft文章。

很难理解为什么。那么类和接口之间只有数据变量有什么区别。

在语言中拥有数据变量意味着将分配存储。

为什么接口应该有数据变量。难道不应该只允许上课吗?

interface ICustomerShort
{
Id: number;
FullName: string;
}

简单的答案是:因为Java和TypeScript是不同的语言,所以它们的行为可能不同。然而,我自己也喜欢理解为什么语言结构是这样的。所以,让我们潜水吧!

首先,我们需要知道 TypeScript 是 JavaScript 的超集。从本质上讲,每个有效的JavaScript程序也是一个有效的TypeScript程序。事实上,TypeScript 被转译为 JavaScript,所以最终,一切都是 JavaScript。但是,TypeScript 提供的是编译时类型检查。

接下来要注意的是,JavaScript 和 TypeScript 都是鸭式语言。然而,在这两种情况下,鸭子打字是不同的。让我们先看一个 JavaScript 示例:

var person = {
name: 'John Doe'
};
console.log(person.age);

在上面的代码中,访问了personage的属性。但是此属性不存在。为此,JavaScript 具有undefined值,这就是返回的值。这是 JavaScript 中极端类型化的一个例子。

现在 TypeScript 提供了额外的类型检查,使其在类型方面更像 Java。让我们考虑以下 TypeScript 代码:

interface Person {
name: string
age: number
}
function printPerson(person: Person) {
console.log(person);
}
class PersonClass {
name: string
age: number
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
const personObject = new PersonClass('Jane Doe', 23);
printPerson(personObject);
const person = {
name: 'John Doe',
age: 42
};
printPerson(person);
const notAPerson = {
name: 'Oops'
}
printPerson(notAPerson);

Playground example

首先,定义了一个interface Person。它还强制只有具有string属性namenumber属性age的对象才被视为Person

接下来,我们定义一个打印Person的方法。

然后,我们定义一个具有name属性和age属性的类PersonObject。请注意,我们不引用PersonObject类中的Person接口。

现在,当我们实例化一个PersonObject时,我们可以将 is 传递给printPerson(...)-类,因为每个PersonObject都符合Person接口并被转换。

我们可以对内联声明的对象(const person = { name: 'John Doe', age: 42 };(做同样的事情:它也符合接口,因此可以传递给printPerson(...)

最后,我们有一个内联对象,它有一个name,但没有age(const notAPerson = { name: 'Oops' }(,因此不满足Person接口。转译器会抱怨。但是请注意,转译器可能仍会生成 JavaScript 代码(取决于转译器设置(,并且生成的 JavaScript 代码将执行"错误"调用,因为 JavaScript 中不可能阻止调用。


编辑

感谢@kaya3向我指出以下内容。

TypeScript 的打字系统基于结构打字。它基于编译时类型检查,而不是运行时类型检查(鸭子类型就是这样做的(。

最新更新