TypeScript入门:对象类型的接口

1,456 阅读3分钟

接口的定义

接口可以约束函数、对象、类的结构和类型,接口使用interface去定义

interface Myinterface {
  //...
}

如何使用

如果后端返回一个列表,如何判断后端返回来的结果符合前端定义的接口呢?

// 定义一个List接口
interface List {
    id: number;
    name: string;
}
// 使用List接口定义Result接口
interface Result {
    data: List[]
}
// render接收后端返回来的result,result要满足Result接口
function render(result: Result) {
    result.data.forEach((value) => {
        console.log(value.id, value.name)
    })
}
// 这个result满足Result接口
let result = {
    data: [
        {id: 1, name: 'A', sex: 'male'},
        {id: 2, name: 'B', age: 10}
    ]
}
render(result)

如果result是下面的值,也满足Result接口,只要result的属性满足接口的必要条件就可以通过ts的类型检查,就是说result中list的属性除了要满足Result中定义的属性,还可以添加更多的属性,就像下面的代码,添加sex: 'male'属性

let result = {
    data: [
        {id: 1, name: 'A', sex: 'male'},
        {id: 2, name: 'B'}
    ]
}

注意如果直接把上面对象字面量作为参数传递给render函数是会报错的

有三种办法解决上面的报错警告:

  1. 把字面量对象赋值给一个变量,把变量传给render函数
let result = {
    data: [
        {id: 1, name: 'A', sex: 'male'},
        {id: 2, name: 'B'}
    ]
}
render(result)
  1. 使用类型断言(as),明确告诉编译器这是一个满足Result接口的对象
render({
  data: [
      {id: 1, name: 'A', sex: 'male'},
      {id: 2, name: 'B'}
  ]
} as Result)
// 不建议使用下面这种,会在React中产生歧义
render(<Result>{
  data: [
      {id: 1, name: 'A', sex: 'male'},
      {id: 2, name: 'B'}
  ]
})
  1. 使用字符串索引签名,使用任意的string索引List,得到任意的结果
interface List {
    id: number;
    name: string;
   [x: string]: any;
}

意思就是使用任意的string索引List,得到任意的结果,这样list就可以添加任意的属性来

如果render添加一个逻辑判断list是否有age属性

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

那么接口List应该添加一个可选属性age?

interface List {
    id: number;
    name: string;
    age?: number;
}

如果给id加一个readonly, 那么id是只读的,不可以修改

interface List {
    readonly id: number;
    name: string;
    age?: number;
}
// 修改result里面list的id就会报错

不确定接口属性个数

如果不确定接口属性的个数,就可以使用有索引属性的接口,既可以用数字,也可以用字符串去索引

  1. 数字索引
interface StringArray {
    [index: number]: string
}
let chars: StringArray = ['a', 'b']

意思是用任意的数字去索引StringArray得到字符串,相当于定义一个字符串类型的数组

  1. 字符串索引
interface Names {
    [x: string]: string;
    // y: number; 不能在字符串索引结果为字符串的接口后面加类型为number的属性,string的话就没问题
    [z: number]: string;
}

用任意的字符串去索引Names,得到的结果是字符串,但是不能在后面去声明一个number类型的属性y: number,因为两种索引签名是可以混用的,如果在后面加上[z: number]: string,那么既可以用字符串去索引Names也可以用数字去索引Names注意数字索引的返回值一定要是字符串索引返回值的子类型,因为ts编译时会进行类型转换,将number转换成string,这样就能保持js的兼容性。

interface Names {
    [x: string]: string;
    [z: number]: number; // number类型不是string的子类型,会报错
}

interface Names {
    [x: string]: any;
    [z: number]: number; // number类型是any的子类型,可以通过
}