接口interface

对象类型接口

定义接口

interface List {
  id: number;
  name: string;
}
interface Result {
  data: List[]
}
function render(result: Result) {
  result.data.forEach((value) => {
    console.log(value.id, value.name)
  })
}
let result = {
  data: [
    {id: 1, name: 'A'},
    {id: 2, name: 'B'}
  ]
}
render(result)  // 1 "A"
                // 2 "B"

PS: 
  后端有时候会传来约定之外的字段,ts并不报错。所以只要传入的对象是必要条件就是被允许的:  
  let result = {
    data: [
      {id: 1, name: 'A', sex: 'male'},
      {id: 2, name: 'B'}
    ]
  }

  但是我们直接传入对象字面量,ts就会对额外的字段进行类型检查: 
  render({
    data: [
      {id: 1, name: 'A', sex: 'male'}, // 提示错误
      {id: 2, name: 'B'}
    ]
  }) 

绕过类型检查的方法

第一种方式: 将对象赋值给一个变量
第二种方式是类型断言:as + 对象的类型,明确告诉编译器,对象的类型就是Result,编译器就会绕过类型检查

render({
  data: [
    {id: 1, name: 'A', sex: 'male'}, // 提示错误
    {id: 2, name: 'B'}
  ]
} as Result)

PS:
  类型断言的另一种不建议用的方法,就是在对象前面加上<Result>,但是在React种容易产生歧义。

第三种方法是使用字符串索引签名,格式如下:

interface List{
	id:number;
	name:string;
	[x,string]:any;
}
PS:
    该签名的含义是用任意的字符串去索引List,会得到任意的结果,这样List就支持多个属性了。

可选属性(属性+格式)

假设有个新需求,需要判断value中是否有个新字段,如果有,就把它打印出来:

interface List {
  id: number;
  name: string;
  age?: number;
}
interface Result {
  data: List[]
}
function render(result: Result) {
  result.data.forEach((value) => {
    console.log(value.id, value.name)
    if(value.age) {
      console.log(value.age)
    }
  })
}
let result = {
  data: [
    {id: 1, name: 'A', sex: 'male'},
    {id: 2, name: 'B'}
  ]
}
render(result)

PS:
    在render函数中进行判断,会提示错误,这时我们在List中添加属性age,result会报错,这就需要我们使用可选属性了。

只读属性(readonly + 属性格式)

只读属性不允许修改

interface List {
  readonly id: number;
}
function render(result: Result) {
  result.data.forEach((value) => {
    value.id ++   // 提示错误
  })
}

可索引类型的接口

以上属性的个数是固定的,当我们不确定属性个数时,就要用到可索引类型的接口,常用的有两种:
用数字索引的接口

interface StringArray {
  [index: number]: string
}

PS:
    含义是用任意的数字去索引StringArray,会得到一个string,这就相当于声明了一个字符串类型的数组。
比如: 
   let chars: StringArray = ['A', 'B']

用字符串索引的接口

interface Names {
  [x: string]: string
}

PS:
    含义是用任意的字符串索引Names,得到的结果都是string,这样我们就不能并列声明number类型的成员了:  
  interface Names {
    [x: string]: string
    y: number   // 提示错误
    z: string
  }

这两种索引签名是可以混用的

interface Names {
  [x: string]: string
  [z: number]: string
}

PS:
    需要注意的是,数字索引签名的返回值一定要是字符串索引签名返回值的子类型,这是因为js会进行类型转换,将number转成string,这样就能保证类型的兼容性。
比如下面这样就会报错:  
  interface Names {
    [x: string]: string
    [z: number]: number   // 提示错误
  }
但这样就可以:  
  interface Names {
    [x: string]: any
    [z: number]: number
  }

函数类型接口

定义接口

用变量定义函数类型

let add: (x: number, y: number) => number

用接口定义函数类型

interface Add {
  (x: number, y: number): number
}

用类型别名定义函数类型

type Add = (x: number, y: number) => number
let add: Add = (a, b) => a + b

混合类型的接口
这种接口既可以定义一个函数,也可以像对象一样拥有属性和方法

interface Lib {
  (): void
  version: string
  doSomething(): void
}
let lib: Lib = (() => {}) as Lib
lib.version = '1.0'
lib.doSomething = () => {}

我们可以创造多个lib实例

function getLib() {
  let lib: Lib = (() => {}) as Lib
  lib.version = '1.0'
  lib.doSomething = () => {}
  return lib
}
let lib1 = getLib()
lib1()
lib1.doSomething()
let lib2 = getLib()
posted @ 2020-04-07 11:21  我要去流浪  阅读(292)  评论(0编辑  收藏  举报