看到网上已经有好多人介绍这两者的区别,本人是恰好学到这里,然后做点自己的学习笔记,给后面学习的小伙伴留下点足迹.话不多说,往下看。
不同点
语法上
type 和 interface 的语法不一样,type 需要等号,而 interface 不需要等号
// interface 声明的类型检查 interface User { name: String age: number sayHello: () => void sayHi(): void } // 类型别名声明的类型检查 type UserType = { name: String age: number sayHello: () => void sayHi(): void }
定义的类型上
- 接口主要声明的是函数和对象,并且总是需要引入特定的类型
- 类型别名声明的可以是任何的数据类型(基本类型别名,联合类型,元组等类型)
// 接口声明的类型检查 // 定义一个对象 interface Point { x: number; y: number; } // 定义一个函数 interface SetPoint { (x: number, y: number): void; // 或者 (x:number, y:number): () => void } // 类型别名定义的类型检查,例如 type Point = { x: number; y: number; }; type SetPoint = (x: number, y: number) => void; // 定义原生类型 type Name = string; // 对象 type PartialPointX = { x: number; }; type PartialPointY = { y: number; }; // 联合类型 type PartialPoint = PartialPointX | PartialPointY; // 元组 type Data = [number, string]; ...
扩展的方式不一样
- 接口可以使用 extends 关键字来进行扩展(这个继承是包含关系,如果父级有了,子集不可以声明重复的,会报错的),或者是 implements来进行实现某个接口
- 类型别名也可以进行扩展,使用 &符号进行(这个继承是合并关系,如果父级有了一个类型,子集还可以声明,但是类型就是变成 &;)这个叫做交叉类型
注意,虽然说 类型别名可以 这样父级和子级声明相同的类型,但是在类型检查会类型推导成其他的,这样使用可能会导致定义的类型与预期不符合
合并声明
- 接口可以定义一个名字,后面的接口也可以直接使用这个名字,自动合并所有的声明,可以理解类似为继承,但是不建议这么使用,还是使用extends关键字好
// interface能够声明合并 interface User { T1: string } interface User { T2: number } /* User 接口为 { T1: string T2: number } */
- 类型别名不能这么使用,会直接报错
实例类型进行赋值
- 接口 没有这个功能
- 类型别名 可以使用 typeof 获取实例的 类型进行赋值(下面的代码在浏览器环境下)
let div = document.createElement('div'); type B = typeof div
类型映射
- 接口 没有这个功能
- 类型别名 可以通过 in来实现类型映射,如下:
type Keys = "firstname" | "lastname" type DudeType = { [key in Keys]: string } const test: DudeType = { firstname: "323", lastname: "332" }
最大的不同
接口可以被类实现,而类型别名不可以
接口是用来表达某个类是否拥有某种能力的,其实这就是实现了接口
我们有一个这样的场景,学生都会学会许多的技能,技能可以从没有,然后到有,然后再到没有。这个怎么来设计类。
这里我们可以进行分析,我们可以设计好多个基类,每一个基类分别代表不同的技能,然后在进行继承,但是大家似乎忘记了,类的继承是单继承,不能多继承哦?类的继承,但是我们怎么来实现上面的场景呢? 使用接口, 理论上一个类可以实现n 个接口
interface ISing { sing:() => void; } interface IDance{ dance: () =>void } class littleStudent implements ISing, IDance{ // 这里必须实现接口的方法,是强约束力的。 sing(){ }; dance(): void{ } }
接口可以继承类,类型别名不行
接口可以多继承类,表示该类的所有成员都在接口中。如下
相同点
两者都不会出现在编译结果里面
// 接口声明的类型检查 interface User{ name: String age: number sayHello: () => void sayHi(): void } // 类型别名声明的类型检查 type UserType = { name: String age: number sayHello: () => void sayHi(): void } const user: User = { name: 'test', age: 12, sayHello: () => { }, sayHi: () => { } }
编译对比结果如下:
两者都可以进行扩展
只是拓展的方式不一样而已,具体查看上面的拓展
// interface extends interface interface Name { name: string; } interface User extends Name { age: number; } // type extends type type Name = { name: string } type User = Name & { age: number } // interface extends type interface User extends Name // type extends interface interface Name { name: string } type user = Name & { age: number }
描述函数和对象
// interface interface User { name: string age: number (name: string, age; number): void } // type type User = { name: string age: number } type setProps = (name: string, age: number) => void
总结
一般来说,如果不清楚什么时候用interface/type,能用 interface 实现,就用 interface , 如果不能就用 type 。其他更多详情参看 官方规范文档