「这是我参与2022首次更文挑战的第16天,活动详情查看:2022首次更文挑战」。
前言
我在学习 TS 时遇到了一个问题:
比如下面这个例子,可以用 type,也可以用 interface。
interface Person {
name: string
age: number
}
const person: Person = {
name: 'lin',
age: 18
}
type Person = {
name: string
age: number
}
const person: Person = {
name: 'lin',
age: 18
}
那 type 和 interface 难道都可以随便用,总得有个区别吧。
于是我去翻 ts 的文档,想学习一下两者的区别。
真的很想吐槽一下 TypeScript 的 官方文档,没有搜索 API 的功能,很难找到答案,只能慢慢去翻,结果翻了半天也没翻到。
最后去查阅了很多其他资料才知道,type 叫类型别名,藏在高级类型这一篇里,我一个初学者,能翻得到才有鬼!
既然如此,那 interface 和 type 应该是不同的东西才对,一个叫接口,一个叫类型别名。只是有时候两者都能实现同样的功能,才会经常被混淆。
interface
interface(接口) 是 TS 设计出来用于定义对象类型的,可以对对象的形状进行描述。
interface Person {
name: string
age: number
}
const person: Person = {
name: 'lin',
age: 18
}
type
type (类型别名),顾名思义,类型别名只是给类型起一个新名字。它并不是一个类型,只是一个别名而已
就像 NBA 球员 扬尼斯-阿德托昆博,名字太长难记,我们叫他字母哥
。
就像我们项目中配置 alias
,不用写相对路径就能很方便地引入文件
import componentA from '../../../../components/componentA/index.vue'
变成
import componentA from '@/components/componentA/index.vue
有了 type,我们书写 TS 的时候可以更加方便简洁。
比如下面这个例子,getName
这个函数接收的参数可能是字符串,可能是函数,就可以这么写。
type Name = string
type NameResolver = () => string
type NameOrResolver = Name | NameResolver // 联合类型
function getName(n: NameOrResolver): Name {
if (typeof n === 'string') {
return n
}
else {
return n()
}
}
这样调用时传字符串和函数都可以。
getName('lin')
getName(() => 'lin')
如果传的格式有问题,就会提示。
两者相同点
都可以定义一个对象或函数
定义对象前面已经说了,我们来看一下如何定义函数。
type addType = (num1:number,num2:number) => number
interface addType {
(num1:number,num2:number):number
}
这两种写法都可以定义函数类型
const add:addType = (num1, num2) => {
return num1 + num2
}
都允许继承(extends)
我们定义一个 Person 类型和 Student 类型,Student 继承自 Person,可以有下面四种方式
interface 继承 interface
interface Person {
name: string
}
interface Student extends Person {
grade: number
}
const person:Student = {
name: 'lin',
grade: 100
}
type 继承 type
type Person = {
name: string
}
type Student = Person & { grade: number } 用交叉类型
interface 继承 type
type Person = {
name: string
}
interface Student extends Person {
grade: number
}
type 继承 interface
interface Person {
name: string
}
type Student = Person & { grade: number } 用交叉类型
interface 使用 extends 实现继承, type 使用交叉类型实现继承
两者不同点
type 可以,interface 不行
类型别名会给一个类型起个新名字。 类型别名有时和接口很像,但是可以作用于原始值,联合类型,元组以及其它任何你需要手写的类型。 -- TS 文档
声明基本类型、联合类型、交叉类型、元组
type Name = string // 基本类型
type arrItem = number | string // 联合类型
const arr: arrItem[] = [1,'2', 3]
type Person = {
name: Name
}
type Student = Person & { grade: number } // 交叉类型
type Teacher = Person & { major: string }
type StudentAndTeacherList = [Student, Teacher] // 元组类型
const list:StudentAndTeacherList = [
{ name: 'lin', grade: 100 },
{ name: 'liu', major: 'Chinese' }
]
interface可以,type 不行
合并重复声明
interface Person {
name: string
}
interface Person { // 重复声明 interface,就合并了
age: number
}
const person: Person = {
name: 'lin',
age: 18
}
重复声明 type ,就报错了
type Person = {
name: string
}
type Person = { // Duplicate identifier 'Person'
age: number
}
const person: Person = {
name: 'lin',
age: 18
}
小结
interface 和 type 被 TS 设计出来,是完全不同的东西,有各自的职责。
interface 是接口,用于描述一个对象。
type 是类型别名,用于给各种类型定义别名,让 TS 写起来更简洁、清晰。
只是有时候两者都能实现同样的功能,才会经常被混淆,相信看完本文你能分清他俩了。
平时开发中,一般使用组合或者交叉类型的时候,用 type。
一般要用类的 extends 或 implements 时,用 interface。
其他情况,比如定义一个对象或者函数,就看你心情了。
如果我的文章对你有帮助,点赞👍是你对我最大的支持^ _ ^
传送门
「1.9W字总结」一份通俗易懂的 TS 教程,入门 + 实战!
参考文章