Skip to content
导航栏

TS接口

作者:winter wang
更新于:11 天前
字数统计:1.3k 字
阅读时长:5 分钟
阅读量:

接口(Interface)是什么?

相比JavaScript,typescript中的接口(Interface)是一个新的概念,首先来了解一下接口到底是什么?

接口声明(interface declaration)是命名对象类型的另一种方式,它能将多个类型注解合并成一个类型注解。用来约束对象函数的结构。

下面分别用接口约束不同类型变量的结构

约束对象的结构

对象作为函数的参数,使用接口进行约束

ts
interface Person {
  name: string
  sayHello(): void
}

function fn(per: Person) {
  per.sayHello()
}

fn({ name: '孙悟空', sayHello() { console.log(`Hello, 我是 ${this.name}`) } })

约束对象时还可以定义可选成员、只读成员、动态成员

ts
interface Post {
  title: string
  content: string
  subtitle?: string // 可选成员
  readonly summary: string // 只读成员
  [prop: string]: string // 动态成员 【可索引类型】
}

const hello: Post = {
  title: 'yk',
  content: 'ykjun nb',
  summary: 'ykjun',
  yk: 'ykyk'
}

hello.kk = 'kk'

【补充】可索引类型

不确定对象中属性的个数时,可以使用可索引类型的接口

可索引类型具有一个索引签名,它描述了对象索引的类型,还有相应的索引返回值类型

比如:约束字符串数组

ts
interface StringArr {
  [index: number]: string
}

const stringArr: StringArr = ['a', 'b', 'c']

约束函数的结构

ts
interface Add {
  (a: number, b: number): number // 约束函数的类型结构
}

const add: Add = function (a, b) {
  return a + b
}

比如对象中有一个字段是一个函数,使用接口约束就比较方便

ts
interface Obj {
  name: string
  add: Add
}

约束对象数组

ts
interface List {
  readonly id: string // 只读属性
  name: string // 末尾可以用逗号,其实应该用分号,所以可以省略符号
  sex?: string // 可选属性
  [x: string]: any // 字符串索引签名,让List可以支持多个属性
}

interface Result {
  data: List[]
}

function render(result: Result) {
  result.data.forEach((value) => {
    console.log(value.id, value.name)
  })
}

const result: Result = {
  data: [
    { id: 1, name: 'YK', sex: 'male' },
    { id: 2, name: 'yk', phone: 1234 }
  ]
}

render(result)

接口与类

类可以实现接口

使用接口来约束类成员,使用implements实现接口,约束类的属性和方法的类型。类实现接口,必须要实现接口定义所有的属性。接口只能约束类的公有成员,不能约束类的构造函数。

ts
interface Human {
  name: string
  eat(): void
}

class Asian implements Human {
  name: string
  constructor(name: string) {
    this.name = name
  }

  eat() {}
}

一个类还可以实现多个接口

ts
interface Eat {
  eat(food: string): void
}

interface Run {
  run(distance: number): void
}

class Person implements Eat, Run {
  eat(food: string): void {
    console.log(`坐着吃饭: ${food}`)
  }

  run(distance: number) {
    console.log(`直立行走:${distance}`)
  }
}

class Animal implements Eat, Run {
  eat(food: string): void {
    console.log(`啃着吃: ${food}`)
  }

  run(distance: number) {
    console.log(`爬行:${distance}`)
  }
}

接口继承

对接口使用 extends关键字允许我们有效的从其他声明过的类型中拷贝成员,并且随意添加新成员。接口也可以继承多个类型

ts
interface Human {
  name: string
  eat(): void
}

interface Man extends Human {
  run(): void
}
interface Child {
  cry(): void
}

// 继承多个接口
interface Boy extends Man, Child {}

const boy: Boy = {
  name: '',
  run() {},
  eat() {},
  cry() {},
}

接口还可以继承类,相当于把类的成员抽象出来(只有类的成员结构,没有具体实现)

ts
class Auto {
  state = 1
  private state2 = 0
}

// 接口继承类
interface AutoInterface extends Auto {

}

// 类实现接口
class C implements AutoInterface {
  state = 1
}

类继承父类实现接口
class Bus extends Auto implements AutoInterface {

}

最后总结一下接口与类关系

  • 接口之间可以相互继承,这样能够实现接口的复用
  • 类之间可以相互继承,可以实现属性和方法的复用
  • 类可以实现接口,接口只能约束类的公有成员
  • 接口可以继承类的成员,包括公有、私有和受保护成员

image.png

接口与抽象类的区别

抽象类做为其它派生类的基类使用,它们一般不会直接被实例化,不同于接口,抽象类可以包含成员的实现细节

接口与类型别名

类型别名和接口非常相似,大部分时候,你可以任意选择使用。接口的几乎所有特性都可以在 type 中使用,两者最关键的差别在于类型别名本身无法添加新的属性,而接口是可以扩展的。

扩展

ts
// Interface
// 通过继承扩展类型
interface Animal {
  name: string
}

interface Bear extends Animal {
  honey: boolean
}

const bear = getBear()
bear.name
bear.honey

// Type
// 通过交集扩展类型
interface Animal {
  name: string
}

type Bear = Animal & {
  honey: boolean
}

const bear = getBear()
bear.name
bear.honey

添加新的属性

ts
// Interface
// 对一个已经存在的接口添加新的字段
interface Window {
  title: string
}

interface Window {
  ts: TypeScriptAPI
}

const src = 'const a = "Hello World"'
window.ts.transpileModule(src, {})

// Type
// 创建后不能被改变
interface Window {
  title: string
}

interface Window {
  ts: TypeScriptAPI
}

// Error: Duplicate identifier 'Window'.

接口可能只会被用于声明对象的形状,不能重命名原始类型

ts
// Here's two examples of
// using types and interfaces
// to describe an object

interface AnObject1 {
  value: string
}

interface AnObject2 {
  value: string
}

// Using type we can create custom names
// for existing primitives:

type SanitizedString = string
type EvenNumber = number

// This isn't feasible with interfaces
interface X extends string {

}

接口与类型别名的区别更多阅读:常见类型_TypeScript中文文档 (yayujs.com)

Contributors

winter wang