Typescript 中类型和接口的区别
初学者通常会对TypeScript 中的类型和接口感到困惑,特别是如果他们是类型化编程语言的新手。从 TypeScript 入手很简单,但有时我们需要更多地考虑我们的最佳用例。在这种情况下,类型还是接口?
类型和类型别名
在我解释类型和接口之间的区别之前,我们需要弄清楚一些事情。
在 TypeScript 中,我们有很多基本类型,例如字符串、布尔值和数字。此外,TypeScript 允许您使用称为“类型别名”的类型关键字为类型创建新名称。这对于构建更具表现力和不言自明的代码或更容易引用复杂类型很有用。
下面是一个使用类型别名的例子:
type StringOrNumber = string | number;
在此示例中,StringOrNumber是类型的新名称,而不是新类型。我们使用 type 关键字来创建一个新的类型别名。这就是为什么有些人可能会感到困惑,并认为他们只是在为一个类型创建一个新名称时才创建一个新类型。所以当你看到有人在谈论类型和接口之间的区别时,就像在这篇文章中一样,你可以打赌那个人在谈论类型别名和接口。
类型与接口
TypeScript 中的类型是一种指定值形状的方法。它可用于描述对象的预期结构、函数的预期返回类型或变量的类型。类型可以很简单,例如数字或字符串,也可以很复杂,例如对象或数组。
另一方面,接口是描述对象结构的一种方式。它用于定义对象应具有的一组属性及其类型。接口可以由类实现,这意味着类必须具有接口中定义的所有属性和方法。
考虑类型和接口之间差异的一种方法是,类型是一种描述值形状的方式,而接口是一种描述对象形状的方式。
声明合并
接口可以实现但类型不能实现的一件事是声明合并。声明合并是 TypeScript 中的一项功能,它允许您将同名的多个接口组合到一个定义中。
这是声明合并如何工作的示例:
interface IPerson {
name: string;
age: number;
}
interface IPerson {
address: string;
}
// The two declarations of IPerson are merged into a single definition:
// interface IPerson {
// name: string;
// age: number;
// address: string;
// }
在此示例中,IPerson 的两个声明合并为一个定义,其中包括来自第一个接口的name和age属性以及来自第二个接口的address属性。请注意,尝试对类型做同样的事情会抛出错误。
扩展接口
除了声明合并之外,接口还可以用类扩展,这是类型不可能实现的。这是对 OOP 有很大帮助的优秀内容。我们还可以创建执行接口的类。
要扩展接口,可以使用extends关键字,后跟要扩展的接口的名称。例如:
interface Shape {
color: string;
}
interface Square extends Shape {
sideLength: number;
}
在此示例中,Square接口扩展了Shape接口,这意味着任何实现Square接口的对象都必须具有color属性和sideLength属性。
要在类中实现接口,可以使用implements关键字,后跟接口名称。例如:
class Square implements Shape {
color: string;
sideLength: number;
constructor(color: string, sideLength: number) {
this.color = color;
this.sideLength = sideLength;
}
}
在此示例中,Square 类实现了 Shape 接口,这意味着它必须具有颜色属性。该类还有一个 sideLength 属性,这是 Square 接口所必需的。
重要的是要注意,在类中实现接口时,必须包括接口中定义的所有属性和方法。如果您忘记包含它们中的任何一个,您将得到一个编译时错误。
类型交集
在 TypeScript 中,交集类型将多种类型合二为一。它允许您指定一个值可以同时具有多种类型。
以下是您可以如何使用交集类型的示例:
type HasName = { name: string };
type HasAge = { age: number };
type Person = HasName & HasAge;
const person: Person = {
name: "John",
age: 30
};
在此示例中,Person类型是HasName和HasAge类型的交集,这意味着它同时具有 HasName 和 HasAge 类型的属性。person变量属于Person类型,并且可以具有HasName和HasAge属性的值。
一件好事是您还可以创建组合多个接口的新交集类型。但是,您不能创建结合两种类型的接口。
这是一个例子:
interface A {
a: number;
}
interface B {
b: string;
}
type AandB = A & B; //Correct
/*interface AandB {
A & B
}
This will throw an error as it is not possible to intersect types with interfaces.
*/
let ab: AandB = {
a: 42,
b: 'hello'
};
元组
在 TypeScript 中,元组是一种数据类型,表示具有固定数量元素的有序元素列表。元组中的每个元素都可以是不同的类型。
下面是 TypeScript 中元组的示例:
let tuple: [string, number];
tuple = ["hello", 10]; // valid
tuple = [10, "hello"]; // invalid
在上面的例子中,元组有两个元素:一个字符串和一个数字。第一个元素必须是字符串,第二个元素必须是数字。尝试以错误的顺序分配元素的数组将导致类型错误。
元组通常与类型一起使用,但如果您愿意,也可以将元组与接口一起使用。
例如:
interface Tuple {
0: string;
1: number;
}
let tuple: Tuple;
tuple = ["hello", 10]; // valid
tuple = [10, "hello"]; // invalid
在这个例子中,接口 Tuple 定义了元组的结构,第一个元素是一个字符串,第二个元素是一个数字。这允许您使用接口来键入元组变量并确保它具有正确的结构。
我应该使用什么?
在 TypeScript 中选择使用类型还是接口取决于您的具体需求和使用它们的上下文。以下是一些一般准则,可帮助您决定使用哪一个:
当您想要以一般方式描述值的结构时,请使用类型。这可能包括基本类型(如字符串和数字)以及更复杂的类型(如数组和对象)。类型可用于指定变量、函数参数或返回值的类型。
当您想以更具体和严格的方式描述对象的结构时,请使用接口。接口定义了对象应具有的一组属性和方法,并且任何实现该接口的对象都应具有这些属性和方法。当您想要在代码中的对象上强制执行某种结构时,接口是一个不错的选择。
当您想要将类型的灵活性与接口的刚性结合起来时,请同时使用类型和接口。例如,您可以使用类型来描述对象的一般结构,然后使用接口来描述具有附加属性或方法的该对象的更具体版本。
结论
总之,类型和接口是 TypeScript 中的重要概念,可用于强制代码中的类型一致性和结构。类型是描述值结构的更通用的方式,可以包括基本类型(如字符串和数字)以及更复杂的类型(如数组和对象)。接口是一种更具体、更严格的描述对象
结构的方式,定义了对象应具有的一组属性和方法。类型和接口在不同情况下都有用,了解两者之间的区别以及何时使用它们很重要,这样才能在项目中有效地使用 TypeScript。
如果你喜欢我的文章,记得关注获取更多的信息。感谢您的阅读,祝您有美好的一天!
