TypeScript接口和类型之间的区别
在 TypeScript 中,你可能已经注意到,声明自定义类型有两种不同的方式。一种是使用 ` interfacetype` 关键字,另一种是使用 ` typetype` 关键字。因此,你可能会疑惑为什么同一件事有两种方法——你并不孤单。我在TypeScript 自定义类型声明指南中已经介绍过如何使用接口和类型——但让我们更深入地了解一下它们之间的区别。
1. 接口的语法与类型不同。
如果在 TypeScript 中定义了一个类型,那么之后就无法对其进行扩展。例如,考虑一下我刚刚创建的这个自定义类型:
type user = {
name: string,
age: number
}
如果定义完成后,我突然意识到还想添加地址,可以使用以下语法:
type userWithAddress = user & {
address: string
}
使用接口,我们也可以实现同样的功能,但语法略有不同:
interface user {
name: string;
age: number;
}
interface userWithAddress extends user {
address: string
}
现在userWithAddress包含了 的所有属性user,外加一个附加属性——即address。
这两种类型扩展方式的唯一区别在于它们处理冲突的方式。例如,如果您扩展一个接口并引用了一个已定义的属性,则会抛出错误。例如,以下代码将无法正常工作:
interface user {
name: string;
}
interface newUser extends user {
name: number;
}
同时,使用type,你可以这样做:
type user = {
name: string
}
type newUser = user & {
name: number
}
虽然这样做不会报错,但可能会导致一些意想不到的结果——所以应该尽可能避免。例如,上面的name属性被简化为类型never——因为一个类型可以同时never是和string。 :)number
2. 接口可以合并,类型则不能。
同样,`type`types不能合并,而interfaces如果多次声明则可以合并。例如,如果我们有一个类型 `type`,我们不能这样做:
type cat = {
name: string
}
type cat = {
color: string
}
实际上,上面的代码会抛出错误。而使用 `[]` interface,我们可以做到这一点——它会将两个声明合并。因此,下面的示例将创建一个名为 `[]` 的类型,它cat同时具有 `[]`name和 ` color[]` 属性:
interface cat {
name: string;
}
interface cat {
color: string;
}
3. 接口不能扩展原语
虽然我们可以创建一个类型作为原始类型的别名,例如 `String` string,interface但不能这样做。例如,如果您想创建一个名为myName`String` 的类型,它始终是字符串类型,我们可以这样做:
type myName = string;
这里,` \`myName成了 `\` 的别名string,所以我们基本上可以在任何地方用 `\ myName` 代替`\`。而`\` 则不具备这种能力。以下写法不能也不会生效:stringinterface
interface myName extends string {
}
4. 类型可以创建联合体,而接口则不能。
我们可以使用type关键字创建联合类型,但不能对接口这样做。例如,这里,userId可以是 `a`string或 `b` number:
type userId = string | number
同时,上述内容无法通过接口实现interface,因为接口定义了对象的形状或类型。
结论
如您所见,`std::vector`type和interface`std::vector` 之间的主要区别取决于您的使用场景。`std::vector` 的几乎所有功能interface在 `std::vector` 中都可用type,这意味着您可能会更频繁地使用 ` typestd::vector`。不过,通常情况下,选择哪种方法取决于个人偏好或哪种方法最适合您的代码库。
总之,请放心,它并不像你最初想象的那样令人困惑——两者interface实际上type都是做同一件事的两种方法!