什么是 Interface ?
接口类似于抽象类,只不过他更加彻底,只提供标准却完全不实现细节。具体表现在,成员字段不可以赋值初始化,方法不可以实现。用来约束对象、函数以及类的结构和类型,是一种代码协作必须遵守的契约
可以把它理解为形状,一个对象需要有什么样的属性,函数需要什么参数或返回什么样的值,数组应该是什么样子的,一个类和继承类需要符合什么样的描述等等。
接口的定义
interface Person{
name: string;
age: number;
say(): string;
}
接口的实现
class Man implements Person{
name: string;
age: number;
constructor(name:string, age:number){
this.name = name;
this.age = age;
}
say(): string{
return "我的名字是 " + this.name +",今年"+ this.age +"岁了"
}
}
接口继承接口
interface Person {
name: string;
age: number;
say(): string;
}
//多接口之间逗号分隔
//interface 接口A extends 接口B, 接口C
interface Chinese extends Person{
run(): string;
}
class Man implements Chinese {
name: string;
age: number;
constructor(name:string, age:number){
this.name = name;
this.age = age;
}
say(): string{
return "我的名字是 " + this.name +",今年"+ this.age +"岁了"
}
run(): string{
return "跑步:跑呀跑呀跑呀跑。"
}
}
接口类型
一、对象 Interface
- 设置需要存在的普通属性 ---> 接口中约束好的确定属性,定义对象变量的时候 不能少也 不能多
- 设置可选属性 ---> 接口中的可选属性,是表示在对象变量中可以不存在
- 设置只读属性 ---> 接口中的只读属性,是表示在对象变量中只能读取不能修改的
- 设置任意属性 ---> 通过 as 或 [propName: string]: any 来制定可以接受的其他额外属性
interface Person {
name: string
bool?: boolean
readonly timeDate: number
[propName: string]: any
}
let per: Person = {
name: 'LBipanda',
bool: true, // 可以设置可选属性 并非必要的 可写可不写
timeDate: + new Date(), // 设置只读属性
arr: [1, 2, 3, "name"] // 设置其他额外属性
}
定义的变量比接口少一些或者多一些属性是不被允许的,并且类型要相同
let per1: Person = {
age: 18, // ❌ 多出来的属性
name: 123 // ❌ 类型错误
}
per.timestamp = 123 // ❌ 只读属性不可修改
per.arr.pop() // ❌ 只读属性不可修改
二、函数 Interface
Interface 还可以用来规范函数的形状。Interface 里面需要列出参数列表返回值类型的函数定义。写法如下:
- 定义了一个函数接口
- 接口接收三个参数并且不返回任何值
- 使用函数表达式来定义这种形状的函数
1、使用接口定义函数
interface Add {
(x: number, y: number): number
}
let myFunc: Add = function(x, y){ //es5
return x+y;
};
let myFunc1: Add = (x, y) =>{ //es6
return x+y;
};
console.log(myFunc(3,6));
console.log(myFunc(6,4));
三、可索引类型的接口
当不能确定接口中有多少个属性时,可以使用可索引类型接口
可索引类型接口可以用数字去索引,也可以用字符串去索引
一、声明一个数字索引类型的接口:
表示用任意数字去索引numberIndex都会得到一个string
索引值必须为 数字
interface NumberIndex {
[x: number]: string
}
// 相当于声明了一个字符串类型的数组
let chars: NumberIndex = ['A', 'B']
console.log(chars[1]);
let man: NumberIndex = {
1: "zhangsan",
"2": "18"
}
console.log(man[2]);
二、字符串索引接口:
声明一个字符串索引类型的接口:
表示用任意的字符串去索引stringIndex得到的结果都是string
interface StringIndex {
[x: string]: string
}
这样声明后,就不能声明number类型的成员了,会报错
let obj: StringIndex = {
name: "LBpanda",
age: "18",
height: "178",
1: 'why' // 正常编译----字符索引签名类型包含一部分数字索引签名类型
}
console.log(obj.name);
interface StringIndex {
[x: string]: string
y: number;// Property 'y' of type 'number' is not assignable to string index type 'string'.
}
三、两种索引签名混用:
interface Indexes {
[x: string]: string
[z: number]: string
}
这样做,接口既可以用数字索引Names,也可以用字符串索引Names
let obj: Indexes = {
name: "LBipnada",
1: "18"
}
注意: 数字索引的注解类型,一定要是字符串索引的注解类型或者是子类型
这是因为JS会进行类型转换,将 number 转换成 string ,这样就能保证类型的兼容性
interface Indexes {
[x: string]: string | number 数字索引的注解类型和字符串索引的注解类型相同
// [x: string]: any 数字索引的注解类型,是字符串索引的注解类型的子类型
[z: number]: number
}
let obj: Indexes = {
name: "LBipnada",
1: 18
}
四、混合类型的接口
什么是混合类型:函数类型的interface,通过添加属性的方式来实现对象的interface;
interface Counter {
(start: number): void // 1️⃣ 如果只有这一个那么这个接口是函数接口
add(): void // 2️⃣ 这里还有一个方法,那么这个接口就是混合接口
log(): number // 3️⃣ 这里还有另一个方法
}
function getCounter(): Counter { // ⚠️ 它返回的函数必须符合接口的三点
let count = 0
//function counter (start: number) { count = start } // counter 方法函数
let counter = <Counter>function counter (start: number) { count = start } // counter 方法函数
counter.add = function() { count++ } // add 方法增加 count
counter.log = function() { return count } // log 方法打印 count
return counter
}
const c = getCounter()
c(10) // count 默认为 10
c.add()
console.log(c.log())
网友评论