typescript(ts) interface 与 type 的异同

看到网上已经有好多人介绍这两者的区别,本人是恰好学到这里,然后做点自己的学习笔记,给后面学习的小伙伴留下点足迹.话不多说,往下看。

不同点

语法上

typeinterface 的语法不一样,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来进行实现某个接口
  • interface typescript 如何给默认值 typescript interface type_赋值

  • 类型别名也可以进行扩展,使用 &符号进行(这个继承是合并关系,如果父级有了一个类型,子集还可以声明,但是类型就是变成 &;)这个叫做交叉类型
  • interface typescript 如何给默认值 typescript interface type_typescript_02

注意,虽然说 类型别名可以 这样父级和子级声明相同的类型,但是在类型检查会类型推导成其他的,这样使用可能会导致定义的类型与预期不符合

合并声明

  • 接口可以定义一个名字,后面的接口也可以直接使用这个名字,自动合并所有的声明,可以理解类似为继承,但是不建议这么使用,还是使用extends关键字好
// interface能够声明合并
interface User {
  T1: string
}

interface User {
  T2: number
}

/*
User 接口为 {
  T1: string
  T2: number
}
*/

interface typescript 如何给默认值 typescript interface type_typescript_03

  • 类型别名不能这么使用,会直接报错

interface typescript 如何给默认值 typescript interface type_User_04

实例类型进行赋值

  • 接口 没有这个功能
  • 类型别名 可以使用 typeof 获取实例的 类型进行赋值(下面的代码在浏览器环境下)
let div = document.createElement('div');
type B = typeof div

interface typescript 如何给默认值 typescript interface type_typescript_05

类型映射

  • 接口 没有这个功能
  • 类型别名 可以通过 in来实现类型映射,如下:
type Keys = "firstname" | "lastname"
type DudeType = {
  [key in Keys]: string
}
const test: DudeType = {
  firstname: "323",
  lastname: "332"
}

interface typescript 如何给默认值 typescript interface type_多继承_06

最大的不同

接口可以被类实现,而类型别名不可以
接口是用来表达某个类是否拥有某种能力的,其实这就是实现了接口

我们有一个这样的场景,学生都会学会许多的技能,技能可以从没有,然后到有,然后再到没有。这个怎么来设计类。

这里我们可以进行分析,我们可以设计好多个基类,每一个基类分别代表不同的技能,然后在进行继承,但是大家似乎忘记了,类的继承是单继承,不能多继承哦?类的继承,但是我们怎么来实现上面的场景呢? 使用接口, 理论上一个类可以实现n 个接口

interface ISing {
  sing:() => void;
}
interface IDance{
  dance: () =>void
}

class littleStudent implements ISing, IDance{
// 这里必须实现接口的方法,是强约束力的。
  sing(){
  };
  dance(): void{
  }
}

interface typescript 如何给默认值 typescript interface type_多继承_07

接口可以继承类,类型别名不行

接口可以多继承类,表示该类的所有成员都在接口中。如下

interface typescript 如何给默认值 typescript interface type_User_08

相同点

两者都不会出现在编译结果里面

// 接口声明的类型检查
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 typescript 如何给默认值 typescript interface type_多继承_09

两者都可以进行扩展

只是拓展的方式不一样而已,具体查看上面的拓展

// 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 。其他更多详情参看 官方规范文档