typescript(ts) interface 与 type 的异同
看到网上已经有好多人介绍这两者的区别,本人是恰好学到这里,然后做点自己的学习笔记,给后面学习的小伙伴留下点足迹.话不多说,往下看。
不同点
语法上
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 。其他更多详情参看 官方规范文档