# 接口

在程序设计里面,接口起到一种限制和规范作用,接口定义了某一批类所需的规范,接口不关心这些类的内部状态数据,也不关心这些类里方法的实现细节,它只规定这些类 里必须提供某些方法,提供这些方法的类就可以满足实际需要。

就是用接口来约束某种数据 默认不能少属性也不能多属性

接口类型:

  • 属性接口
  • 函数接口
  • 可索引接口
  • 类类型接口
  • 接口扩展

# 属性接口/对象约束

比如传入一个对象,里面的属性必须进行类型约束,我们可以用接口来代替。

重名的接口会自动聚合,两个里面的属性都会进行约束。

// 批量约束,其他函数同样可以使用
interface FullName {
  firstName: string;
  lastName: string
}

// 传入的name参数实现FullName约束
function printName(name: FullName):void {
  console.log(name.firstName +'----'+name.lastName)
}

let obj = {
  firstName: 'chang',
  lastName: 'zhen'
}

printName(obj);

# 可选属性与readonly

和可选参数相似,使用 ? 来定义,可传可不传。readonly定义只读属性,表示对象的这个属性定义后不能被修改。

// 可选属性
interface chooseName{
  firstName?: string;
  lastName: string
}

function getName(name: chooseName) {
  console.log(name)
}

getName({
  firstName: 'zhang',
  lastName: 'san'
})
getName({  // 可以不传
  lastName: 'chang'
})

// 只读属性
interface userInfo{
  readonly id: string;
  name: string
}

const obj:userInfo = {
  id: 1,
  name: 'xxx'
}

# 函数类型接口

对方法传入的参数以及返回值进行约束

interface encrypt {
  // 函数的参数类型及返回类型
  (key: string, value: string):string;
}

// 方法里的参数名不需要与接口定义的名相同,但类型要一样
let md5:encrypt = function(keyText:string, valueText:string):string {
  return keyText +'-----'+ valueText
}

console.log(md5('md5header', 'md5footer'))

let sha1:encrypt= function(key:string, value:string):string {
  return key+'----'+value
}
console.log(sha1('sha1header', 'sha1footer'))

# 数组类型接口

普通类型数组是在后面加 string[],接口数组也是一样 interface[]

// 普通类型数组
let arr1:number[] = [2, 2, 1, 44, 5]

// 约束对象数组
interface userArr {
  name:string
}
// 其元素必须满足userArr为一个有name的对象
let arr:userArr[] = [{name: '111'}, {name: '222'}]

# 可索引接口

如果只对数组或对象中的某几个属性进行约束,但是不想全部属性都进行约束,其他的属性我们就可以使用索引接口在[]中不进行约束。

// 数组约束接口
// 对数组的为为数字类型的下标都约束为字符串
interface userArr {
  [index:number]:string
}

let arr:userArr=['str', 'hahah']
console.log(arr)

// 对对象中其他为字符串的属性约束为任意类型
interface userObj {
  name: string;
  age: number;
  [propName: string]: any;
}
let object:userObj = {
  name: 'chang',
  age: 18,
  grade: 100,
  class: 1
}
console.log(object)

# 类类型接口

对类的约束,使用implements关键字来定义

interface Animal {
  name: string
  eat(str?:string):void
}


// 类必须要有name和eat
class Dog implements Animal {
  name:string
  constructor(name:string) {
    this.name = name
  }
  eat(food?:string):void {
    console.log(`${this.name}eat ${food}`)
  }
}

var dog = new Dog('小猫')
dog.eat('老鼠');

# 把类当做接口

class A {
  type: boolean = false
  changeType() {
    this.type = !this.type
  }
}

class B {
  name:string = 'xxx'
  getName():string {
    return this.name
  }
}

class C implements A,B {
  type: boolean = true
  name:string = '123'
  getName():string {
    return this.name
  }
  changeType() {
    this.type = !this.type
  }
}

# 接口继承

接口可以继承接口

interface Person {
  eat(food:string):void;
}

interface Web extends Person {
  work():void;
}

// 必须要实现所有的方法
class Web1 implements Web {
  name:string
  constructor(name:string) {
    this.name = name
  }
  eat(food:string) {
    console.log(`${this.name}eat${food}`)
  }
  work() {
    console.log(`${this.name}工作中`)
  }
}

var w = new Web1('小常');
w.eat('苹果');
w.work();

// 父类

class Programmer {
  name:string
  constructor(name:string) {
    this.name = name
  }
  coding():void {
    console.log(`${this.name}写代码`)
  }
}

// 即继承父类又继承接口
class Web2 extends Programmer implements Web {
  constructor(name:string) {
    super(name)
  }
  eat(food:string) {
    console.log(`${this.name}eat${food}`)
  }
  work() {
    console.log(`${this.name}工作中`)
  }
}

let w2 = new Web2('小李')
w2.coding();