如何定义接口和类型别名?

聊到TypeScript,接口(Interface)和类型别名(Type Alias)绝对是绕不开的两个核心概念。这俩兄弟长得像,干的事儿也经常重叠,新手很容易迷糊。今天咱就用二十年踩坑换来的经验,掰扯清楚它们到底该怎么用。

先看接口,这词儿听着就挺正式,对吧?它主要用来定义对象的“形状”,也就是这个对象应该有哪些属性、分别是什么类型。比如你要定义一个用户对象,用接口就这么干:

interface User {
  id: number;
  name: string;
  email?: string;
}

这就立下规矩了:一个User类型的对象,必须有id(数字)和name(字符串),email呢,后面跟个问号,表示是可选的,可以有也可以没有。接口这东西特别擅长描述对象和类的结构,而且它是可以“扩展”的,也就是继承。你可以基于一个旧的接口,创建一个更具体的新接口:

interface Admin extends User {
  permissions: string[];
}

看,这个Admin接口拥有了User的全部属性,还额外多了个permissions权限数组。这种扩展能力在构建复杂的类型体系时非常顺手。

那类型别名是干嘛的?它更像是一个“类型外号”,用type关键字给任何类型起个新名字。它能干的活儿比接口稍微广一些。最基本的,它也能定义对象形状:

type Point = {
  x: number;
  y: number;
};

这和用接口定义看起来差不多。但类型别名的能耐不止于此。它还能定义联合类型、元组类型,或者是一些复杂的类型组合,这些是接口不太擅长的。

type ID = number | string;
type Coord = [number, number];
type FetchResult = { success: true; data: any } | { success: false; error: string };

比如说ID,它声明这个类型可以是数字或者字符串。Coord定义了一个有两个数字元素的元组。FetchResult这个例子就更实用了,它描述了一个异步请求的结果:要么成功带着数据,要么失败带着错误信息。这种灵活的组合能力是类型别名的一大亮点。

那么问题来了,到底该用哪个?这是我的个人经验,算不上金科玉律,但挺管用:当你主要是为了定义对象或类的结构,尤其是需要用到继承(extends)或实现(implements)时,优先考虑接口。它更符合面向对象的设计思路,而且在错误提示上有时更清晰一点。当你需要定义联合类型、元组,或者需要利用&(交叉类型)进行复杂组合时,类型别名是你的不二之选。

实际上,在现在的TypeScript里,它俩的能力重合度已经很高了。很多场景下你爱用哪个都行,团队统一风格更重要。但记住一个关键区别:接口是开放式的,同名接口可以多次声明,它们会自动合并。类型别名是封闭的,一旦定义就不能再改变。这个特性让接口在扩展第三方库类型或声明全局类型时特别有用。

别把这当成选择题,它们更像是你工具箱里的两把不同的螺丝刀。理解各自的特点,在合适的场景用合适的工具,你的类型定义就会既清晰又强大。

© 版权声明
THE END
喜欢就支持一下吧
点赞15 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容