TypeScript 中 type 和 interface 的异同
interface 和 type 都是可以用来定义数据类型的,大部分场景下,能用 interface
定义的自然也可以用 type
定义,他们两者功能类似,却又有些许区别。
相同点
定义数据类型
- 定义对象/数据模型
interface IUser {
username: string
password: string
}
type User = {
username: string
password: string
}
- 定义函数
interface IUpdateUser {
(name: string, age: number): void
}
const updateUser: IUpdateUser = (name: string, age: number): void => {
}
type UpdateUserHandler = (name: string, age: number) => void
const updateUser: UpdateUserHandler = (name: string, age: number): void => {
}
扩展(extends)
- interface extends interface
interface IParent {
name: string
}
interface IChild extends IParent {
age: number
}
- interface extends type
type Parent = {
name: string
}
interface IChild extends Parent {
age: number
}
const c: IChild = { name: 'zhangsan', age: 18 }
- type extends type
type Parent = {
name: string
}
type Child = Parent & { age: number }
- type extends interface
interface IPerson {
name: string
}
type Person = IPerson & { age: number }
const p: Person = { name: 'zhangsan', age: 18 }
区别
1、 interface 声明合并
对于相同名称的接口,TypeScript 会将他们进行合并成一个;如果用 type 定义了多个相同名称的数据类型,则会报重复定义的错误信息。
interface IUser {
username: string
password: string
}
interface IUser {
username: string // 允许出现重复key, 但是类型必须一致, 如果值类型不相同则会报错
email?: string
}
// TypeScript 会将相同接口进行合并,所以上述代码等价于:
interface IUser {
username: string
password: string
email?: string
}
利用这个特性,我们可以往内置类中添加声明。比如我们在 window
中挂在一个 __APP_VERSION__
属性:
window.__APP_VERSION__ = '1.0.0'
// console.log(window.__APP_VERSION__)
如果我们直接这么写,代码会提示错误信息:Property '__APP_VERSION__' does not exist on type 'Window & typeof globalThis'.
,这是因为内置的 window
对象并未声明 __APP_VERSION__
属性,该属性是我们动态添加上去的,所以我们需要声明一下,告诉 TypeScript 编译器我们有这个属性并且值类型是什么。
declare global {
interface Window {
__APP_VERSION__: string
}
}
添加如上声明后,代码不报错了,并且会有正确的代码提示。
2、 类型别名(type aliases)
type 允许对已存在的数据类型进行重命名(起别名),但是 interface 做不到,interface 只能继承。
type CustomString = string
function toUpperCase(str: CustomString): CustomString {
return str.toUpperCase()
}
console.log(toUpperCase('zhangsan'))
3、type 中允许使用 typeof 来获取数据类型
const name: string = 'zhangsan'
type NameType = typeof name // NameType => string
const name1: NameType = ''
总结
- interface 和 type 均可以定义数据类型,但是 interface 只能定义对象/函数,type 可以定义组合类型、交叉类型、原始类型、元组等
- interface 具有声明合并(
declaration merging
)的特性,但是 type 会报错 - type 可以对数据类型进行重命名,但是 interface 不行
通常你不需要考虑是用 interface 还是 type,你可以根据个人喜好来决定用 interface 还是 type。