Skip to content

使用 interface 定义接口 对象类型接口和函数类型接口 接口可以约束对象,函数,类的结构和类型,是一种代码协作必须遵守的契约

接口事列

typescript
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: 'JS' },
    { id: 2, name: 'TS' },
  ],
}
render(result)

image.png

额外属性

在接口的实际调用中,后端也经常会传递约定之外的字段,如

typescript
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: 'JS', remark: '' }, // 接口约定以外的remark字段
    { id: 2, name: 'TS' },
  ],
}
render(result)

传入接口以外的字段remark是并没有报错,ts允许这种情况的发生

只要传入的对象满足接口的必要条件就可以被允许,即使传入多余的字段也可以通过类型检查

但也有例外,如果直接传入对象字面量,TS就会对额外的字段进行类型检查,如下:

typescript
render({
  data: [
    { id: 1, name: 'JS', remark: '' }, // 接口约定以外的remark字段
    { id: 2, name: 'TS' },
  ],
})

image.png

绕过检查的方法有3种

  1. 将对象字面量赋值给一个变量
typescript
let result = {
  data: [
    { id: 1, name: 'JS', remark: '' }, // 接口约定以外的remark字段
    { id: 2, name: 'TS' },
  ],
}
render(result)
  1. 使用类型断言
typescript
// one
render({
  data: [
    { id: 1, name: 'JS', remark: '' }, // 接口约定以外的remark字段
    { id: 2, name: 'TS' },
  ],
} as Result)

// two
render(<Result>{
  data: [
    { id: 1, name: 'JS', remark: '' }, // 接口约定以外的remark字段
    { id: 2, name: 'TS' },
  ],
})
  1. 使用字符串索引签名

    表示用任意字符串去索引List,可得到任意结果,此时List可以实现支持多个属性

typescript
interface List {
  id: number
  name: string
  [remark: string]: any
}

接口成员

可选属性

对于一个约定好的接口类型,其中有些字段并不是一定会存在的,是可选属性 而之前在接口中声明的字段,是必须要满足的字段,不可以缺少

声明方式:
接口属性? 类型注解

typescript
interface List {
  id: number
  name: string
  // [x: string]: any;
  age?: number
}

interface Result {
  data: List[]
}

function render(result: Result) {
  result.data.forEach((value) => {
    console.log(value.id, value.name) // 1 "JS"  2 "TS"
    if (value.age) {
      console.log(value.age) // 10
    }
  })
}

let result = {
  data: [
    { id: 1, name: 'JS', remark: '' }, // 接口约定以外的remark字段
    { id: 2, name: 'TS', age: 10 },
  ],
}
render(result)

只读属性

有时候我们希望对象中的一些字段只能在创建的时候被赋值,那么可以用 readonly 定义只读属性

typescript
interface List {
  readonly id: number // 只读属性
  name: string
  // [x: string]: any;
  age?: number
}

interface Result {
  data: List[]
}

function render(result: Result) {
  result.data.forEach((value) => {
    console.log(value.id, value.name) // 1 JS"  2 "TS"
    if (value.age) {
      console.log(value.age) // 10
    }
    value.id++ // 修改只读属性
  })
}

let result = {
  data: [
    { id: 1, name: 'JS', remark: '' },
    { id: 2, name: 'TS', age: 10 },
  ],
}
render(result)

image.png

可索引类型的接口

数字索引接口

声明一个数字索引类型的接口 表示用任意数字去索引 number Index都会得到一个 string

typescript
interface StringArray {
  [index: number]: string
}

// 相当于声明了一个字符串类型的数组
let chars: StringArray = ['A', 'B']

字符串索引接口

声明一个字符串索引类型的接口 表示用任意的字符串去索引 string Index 得到的结果都是 string

typescript
interface stringIndex {
  [x: string]: string
}

// 这样声明后,就不能声明 number 类型的成员了,会报错
interface stringIndex {
  [x: string]: string
  y: number // Property 'y' of type 'number' is not assignable to string index type 'string'.
}

两种索引签名混用

注: 数字索引的返回值,一定要是字符串返回类型的子类型 这是因为JS会进行类型转换,将number转换成string,这样就能保证类型的兼容性

typescript
// 在上边的字符串索引接口stringIndex中,添加数字索引签名
interface stringIndex {
  [x: string]: string
  [z: number]: string
}

// 如:将数组索引的返回值改成number
// interface Names {
// 	[x: string]: string;
// 	// y: number;
// 	[z: number]: number;
// }

interface Names {
  [x: string]: any
  // y: number;
  [z: number]: number
}

image.png

学习笔记出自于梁宵老师课程