一、前言

TS新增了一个重要概念:接口,分为对象类型接口和函数类型接口
接口可以约束对象,函数,类的结构和类型,是一种代码协作必须遵守的契约

接口的定义方式:

使用interface关键字

二、对象类型接口

接口中可定义 确定属性、可选属性、任意属性、只读属性

1、确定属性

typescript in typeScript interface 数组属性_字符串

interface UserInfo {
  name: string;
  age: number;
}

const myInfo: UserInfo = {
  name: "haha",
  age: 20
};

typescript in typeScript interface 数组属性_字符串

接口中约束好的确定属性,定义对象变量的时候 不能少也 不能多

2、可选属性

typescript in typeScript interface 数组属性_字符串

interface UserInfo {
  name: string;
  age: number;
  sex?:string 
}

const myInfo: UserInfo = {
  name: "haha",
  age: 20
};

typescript in typeScript interface 数组属性_字符串

接口中的可选属性,是表示在对象变量中可以不存在

3、任意属性

typescript in typeScript interface 数组属性_字符串

interface UserInfo {
  name: string;
  age: number;
  sex?:string ;
  [propName: string]:any;
}

const myInfo: UserInfo = {
  name: "haha",
  age: 20,
  test1: 'lala',
  test2: 'ff',
  test3:123
};

typescript in typeScript interface 数组属性_字符串

注:一旦定义了任意属性,那么确定属性和可选属性的类型都必须是任意属性类型的子类;

定义了任意属性后,对象变量中的属性个数才可以出现比接口的属性数量多的情况

4、只读属性

typescript in typeScript interface 数组属性_字符串

interface UserInfo {
  readonly id: number;
  name: string;
  age: number;
  sex?: string;
  [propName: string]: any;
}

const myInfo: UserInfo = {
  id: 1,
  name: "haha",
  age: 20,
  test1: "lala",
  test2: "ff",
  test3: 123
};

typescript in typeScript interface 数组属性_字符串

只读属性也是确定属性,在对象变量定义的时候必须有值,此后不能修改

对象接口示例

以查询商品列表接口API为例:

// 接口声明:API协议约定返回格式
interface ResponseData {
    resCode: number;
    resData: ResultData[];
    message: string;
}

// 数据接口声明
interface ResultData {
    productId: number;
    productName: string;
}

符合接口约定的对象:

let resultData = {
    resCode: 0,
    resData: [
        { productId: 1, productName:"TypeScipt实战" },
        { productId: 2, productName:"TypeScipt从入门到精通" },
    ],
    message: "success"
}

输出函数对结果进行打印:

function render(res: ResponseData) {
    console.log(res.resCode, res.message)
    res.resData.forEach((obj) => {
        console.log(obj.productId, obj.productName)
    })
}

render(resultData);

输出:

0 "success"
1 "TypeScipt实战"
2 "TypeScipt从入门到精通"

额外属性

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

let resultData = {
    resCode: 0,
    resData: [
        { productId: 1, productName:"TypeScipt实战", remark:""}, // 接口约定以外的remark字段
        { productId: 2, productName:"TypeScipt从入门到精通" },
    ],
    message: "success"
}

此时,并没有报错,TS允许这种情况的发生

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

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

以下方式会报错:

render({
    resCode: 0,
    resData: [
        { productId: 1, productName:"TypeScipt实战", remark: "备注"},
        { productId: 2, productName:"TypeScipt从入门到精通" },
    ],
    message: "success"
})

 

绕过检查的方法有3种:

1,将对象字面量赋值给一个变量

将对象字面量赋值给一个变量后,在render不再报错:

let result = {
    resCode: 0,
    resData: [
        { productId: 1, productName:"TypeScipt实战", remark: "备注"},
        { productId: 2, productName:"TypeScipt从入门到精通" },
    ],
    message: "success"
}
render(result)
2,使用类型断言
使用类型断言方式,明确告诉编译器类型是什么,编译器就会绕过类型检查

方法1:

object as targetInterface
render({
    resCode: 0,
    resData: [
        { productId: 1, productName:"TypeScipt实战", remark:""},
        { productId: 2, productName:"TypeScipt从入门到精通" },
    ],
    message: "success"
} as ResponseData)

方法二:

<targetInterface>object
render(<ResponseData>{
    resCode: 0,
    resData: [
        { productId: 1, productName:"TypeScipt实战", remark: "备注"},
        { productId: 2, productName:"TypeScipt从入门到精通" },
    ],
    message: "success"
})
3,使用字符串索引签名

添加字符串索引签名:

interface ResultData {
    productId: number;
    productName: string;
    [remark: string]: any;  // 字符串索引签名
}
表示用任意字符串去索引List,可得到任意结果,此时List可以实现支持多个属性

三、函数接口

函数定义方式

1,在TS中,可以使用一个变量直接定义函数:

// 1,使用变量定义函数
let add: (x: number, y: number) => number
= (x, y){
return x+y;
};
add(1,2)

 

2,还可以使用接口来定义函数:

// 2,使用接口定义函数
interface Add {
    (x: number, y: number): number
}
let myFunc: Add = function(x, y){
  return x+y;
};
myFunc(1,2);

 

3,使用类型别名来定义函数:

类型别名使用type关键字,相当于为函数类型起一个名字
// 3,使用类型别名来定义函数
type Add = (x: number, y: number) => number

 

四、可索引类型的接口

当不能确定接口中有多少个属性时,可以使用可索引类型接口
可索引类型接口可以用数字去索引,也可以用字符串去索引
1,数字索引接口:

声明一个数字索引类型的接口:

表示用任意数字去索引numberIndex都会得到一个string
interface numberIndex {
    [x: number]: string
}
// 相当于声明了一个字符串类型的数组
let chars: numberIndex = ['A', 'B']
2,字符串索引接口:

声明一个字符串索引类型的接口:

表示用任意的字符串去索引stringIndex得到的结果都是string
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'.
}
3,两种索引签名混用:
在上边的字符串索引接口stringIndex中,添加数字索引签名
interface stringIndex {
    [x: string]: string
    [z: number]: string
}
这样做.接口既可以用数字索引Names也可以用字符串索引Names

但需要注意:数字索引的返回值,一定要是字符串返回类型的子类型

这是因为JS会进行类型转换,将number转换成string,这样就能保证类型的兼容性

比如:将数组索引的返回值改成number:

interface stringIndex {
    [x: string]: string
    [z: number]: number    // // Numeric index type 'number' is not assignable to string index type 'string'.
}

这样就和String类型不兼容了,要取一个能够兼容number的类型,比如any:

interface stringIndex {
    [x: string]: any
    [z: number]: number // Numeric index type 'number' is not assignable to string index type 'string'.
}