【TypeScript】中接口的详细介绍

文章目录

    • TypeScript接口的使用
      • 接口定义对象类型
      • 接口定义索引类型
      • 接口定义函数类型
      • 接口的继承
      • 交叉类型
      • 接口的实现
      • 接口和type的区别

TypeScript接口的使用

接口定义对象类型

在前面我们通过type可以用来声明一个对象类型

通过类型别名(type), 声明一个对象类型

type InfoType = {
  name: string
  age: number
}

const info: InfoType = {
  name: "chnyq",
  age: 18
}

对象类型的另外一种声明方式, 就是通过接口来声明

通过接口, 声明一个对象类型

interface InfoType {
  name: string
  age: number
}

const info: InfoType = {
  name: "chnyq",
  age: 18
}

使用接口定义时, 有一个规范, 接口名前面加上一个"I", 这个是规范, 遵不遵守看个人意愿

// 接口名前面加上一个大写的I 
interface IInfoType {
  name: string
  age: number
}

const info: IInfoType = {
  name: "chnyq",
  age: 18
}

接口定义对象类型时, 同样可以定义可选类型, 使用方式和之前是一样的

interface InfoType {
  name: string
  // 添加可选类型
  age?: number
}

const info: InfoType = {
  name: "chnyq",
  // age: 18
}

接口也可以定义只读属性, readonly

interface InfoType {
  // 定义只读属性
  readonly name: string
  age: number
}

const info: InfoType = {
  name: "chnyq",
  age: 18
}

两种定义对象类型的方式在使用上的区别,我会在下面讲到, 接下来我们继续学习一下接口的其他特性


接口定义索引类型

前面我们使用interface来定义对象类型,这个时候其中的属性名、类型、方法都是确定的,但是有时候我们会遇 到类似下面的对象

例如我想使用一个对象(正常用数组, 在这里我偏要用对象o.0), 来存放我们前端需要学习的部分技术

const frontLanguage = {
  0: "HTML",
  1: "CSS",
  2: "JavaScript",
  3: "Vue",
  4: "TypeScript"
}

此时我们对象中key是number类型, value是string类型

如果我们想要限制对象后续增加的属性, key也是number类型, value也是string类型的话, 我们可以使用接口定义索引类型进行限制

interface IndexLanguage {
  // 表示索引key为number类型, value为string类型
  // index相当于是形参, 可以自己取名的
  [index: number]: string
}

const frontLanguage: IndexLanguage = {
  0: "HTML",
  1: "CSS",
  2: "JavaScript",
  3: "Vue",
  4: "TypeScript",
  // 再添加其他类型的话就会报错
  // "abc": "12"
}

当然, key不是只能为number类型, value也不是只能为string类型, 这个都是可以自定义的

interface LanguageBirth {
  [name: string]: number
}

const language: LanguageBirth = {
  "Java": 1995,
  "JavaScript": 1996,
  "C": 1972
}

接口定义函数类型

前面我们都是通过interface来定义对象中普通的属性和方法的,实际上它也可以用来定义函数类型

// 接口定义函数类型
interface CalcFun {
  // 固定的语法
  (n1: number, n2: number): number
}

const add: CalcFun = (n1: number, n2: number) => {
  return n1 + n2
}

const mul: CalcFun = (num1: number, num2: number) => {
  return num1 * num2
}

// 测试
console.log(add(10, 20)) // 30
console.log(mul(10, 20)) // 200

当然,除非特别的情况,函数类型还是推荐大家使用类型别名的方式来定义

type CalcFun = (n1: number, n2: number) => number

接口的继承

接口和类一样是可以进行继承的,也是使用extends关键字

interface Swim {
  swimming: () => void
}

// Action接口继承自Swim接口
interface Action extends Swim {}

// 由于Action继承自Swim, 意味着使用Action类型, 同样需要对swimming方法实现
const action: Action = {
  swimming() {
    console.log("swimming")
  }
}

并且我们会发现,接口是支持多继承的(类不支持多继承)

例如下面代码, 我定义两个接口: Swim和Fly, 我们使用一个接口继承自这两个接口

interface Swim {
  swimming: () => void
}

interface Fly {
  flying: () => void
}

// Action接口继承自Swim和Fly接口
interface Action extends Swim, Fly {}

// 意味着使用Action类型, 需要对swimming和flying方法都进行实现
const action: Action = {
  swimming() {
    console.log("swimming")
  },
  flying() {
    console.log("flying")
  }
}

交叉类型

前面我们学习了联合类型

联合类型表示多个类型中一个即可

type IDType = number | string

还有另外一种类型合并方式,就是交叉类型( Intersection Types)

交叉类似表示需要满足多个类型的条件;

交叉类型使用 & 符号;

我们来看下面的交叉类型

表达的含义是number和string要同时满足

但是有同时满足是一个number又是一个string的值吗?其实是没有的,所以MyType其实是一个never类型;

type IDType = number & string

交叉类型的应用

在开发中,我们使用交叉类型时,通常是对对象类型进行交叉的

interface Swim {
  swimming: () => void
}

interface Fly {
  flying: () => void
}

// 定义一个交叉类型
type myType = Swim & Fly
// 使用交叉类型, 需要同时实现Swim和Fly类型的方法
const obj: myType = {
  swimming() {
    console.log("swimming")
  },
  flying() {
    console.log("flying") 
  }
}

也就是说, 我们组合接口就有了两种方式

方式一: 使用接口的多继承

方式二: 交叉类型来结合


接口的实现

接口定义后不仅可以作为类型,接口也是可以被类实现的

实现接口是使用的implements关键字

interface Swim {
  swimming: () => void
}

// 类实现接口
class Action implements Swim {
  swimming() {
    console.log("swimming")
  }
}

类实现接口也是可以进行多实现的

interface Swim {
  swimming: () => void
}

interface Fly {
  flying: () => void
}

// 类多实现接口
class Action implements Swim, Fly {
  swimming() {
    console.log("swimming")
  }
  
  flying() {
    console.log("flying")
  }
}

如果被一个类实现,那么在之后需要传入接口的地方,都可以将这个类传入;

这就是面向接口开发;

// 函数要求传入一个接口
function swim(swimmer: Swim) {
  swimmer.swimming()
}

const act = new Action()
// 由于Action类实现了接口, 所以类可以直接传入
swim(act)

一个类, 是可以同时继承父类, 又实现或者多实现接口

interface Swim {
  swimming: () => void
}

interface Fly {
  flying: () => void
}

class Animal {

}

// 继承父类的同时, 又实现接口
class Action extends Animal implements Swim, Fly {
  swimming() {
    console.log("swimming")
  }

  flying() {
    console.log("flying")
  }
}

接口和type的区别

我们会发现interface和type都可以用来定义对象类型,那么在开发中定义对象类型时,到底选择哪一个呢?

如果是定义非对象类型,通常推荐使用type,比如Direction、 Alignment、一些Function;

如果是定义对象类型,那么他们是有区别的

  • interface可以重复的对某个接口来定义属性和方法;

对于名称相同的接口, 会将属性进行合并

interface Foo {
  name: string
}

interface Foo {
  age: number
}

// name和age都需要定义
const foo: Foo = {
  name: "chenyq",
  age: 18
}

而type定义的是别名,别名是不能重复的;

【TypeScript】中接口的详细介绍_第1张图片

对于定义对象类型, 建议使用interface(官方给的建议也是interface), 也可以根据自己的爱好选择

你可能感兴趣的:(TypeScript,typescript,javascript,前端)