一、接口的定义
在面向对象的编程中,接口是一种规范的定义,它定义了行为和动作的规范,在程序设计里面,接口起到一种限制和规范的作用。接口定义了某一批类所需要遵守的规范,接口不关心这些类的内部状态数据,也不关心这些类里方法的实现细节,它只规定这批类里必须提供某些方法,提供这些方法的类就可以满足实际需要。 typescrip中的接口类似于java,同时还增加了更灵活的接口类型,包括属性、函数、可索引和类等。
二、接口的用途
接口的用途就是对行为和动作进行规范和约束,跟抽象类有点像,但是,接口中不能有方法体,只允许有方法定义。
三、接口用法:
1. 使用interface来定义接口:
interface Info {
firstName: string;
lastName: string;
}
const getFullName = ({ firstName, lastName }: Info) => {
return `${firstName} ${lastName}`;
};
console.log(getFullName({ firstName: '123', lastName: '1231' }));
注意在定义接口的时候,你不要把它理解为是在定义一个对象,而要理解为{}括号包裹的是一个代码块,里面是一条条声明语句,只不过声明的不是变量的值而是类型。声明也不用等号赋值,而是冒号指定类型。每条声明之前用换行分隔即可,或者也可以使用分号或者逗号,都是可以的。
2. 可选属性
接口设置可选属性,在属性名后面加个?即可:
interface Vegetables {
color?: string;
type: string;
}
3. 多余属性检查
getVegetables({
type: "tomato",
size: "big" // 'size'不在类型'Vegetables'中
});
我们看到,传入的参数没有 color 属性,但也没有错误,因为它是可选属性。但是我们多传入了一个 size 属性,这同样会报错,TypeScript 会告诉你,接口上不存在你多余的这个属性。只要接口中没有定义这个属性,就会报错,但如果你定义了可选属性 size,那么上面的例子就不会报错。
4. 绕开多余属性检查
- 什么是接口的多余参数检查
interface Baseinfo {
name:string,
sex?:string
}
// 人
function printPesonInfo(parmasinfo: Baseinfo) {
console.log(`姓名:${parmasinfo.name }`)
}
// 如果直接传递参数,且传递的参数key未在接口中定义会提示错误
printPesonInfo( {name:'wang',age:13} ) // 报错的
- 使用类型断言
类型断言就是用来明确告诉 TypeScript,我们已经自行进行了检查,确保这个类型没有问题,希望 TypeScript 对此不进行检查,所以最简单的方式就是使用类型断言:
interface Baseinfo {
name:string,
sex?:string
}
// 人
function printPesonInfo(parmasinfo: Baseinfo) {
console.log(`姓名:${parmasinfo.name }`)
}
// 利用类型断言,告诉编译器我们传递的参数 就是Baseinfo 接口的东西
printPesonInfo( {name:'wang',age:13} as Baseinfo ) // wang
- 索引签名
interface Baseinfo {
name:string,
sex?:string,
[other:string]:any
}
// 人
function printPesonInfo(parmasinfo: Baseinfo) {
console.log(`姓名:${parmasinfo.name }`)
}
// 接口中的索引签名other 就会收到age
printPesonInfo( {name:'wang',age:13}) // wang
- 利用类型兼容性
interface Baseinfo {
name:string,
sex?:string,
}
// 人
function printPesonInfo(parmasinfo: Baseinfo) {
console.log(`姓名:${parmasinfo.name }`)
}
let paramsinfo = {name:'wang',age:13}
// 类型兼容性就是我们定义的paramsinfo 不管有都少东西,只要包含接口中定义的即可
printPesonInfo(paramsinfo) // 姓名:wang
5. 只读属性
关键字:readonly
const NAME: string = "Lison";
NAME = "Haha"; // Uncaught TypeError: Assignment to constant variable
const obj = {
name: "lison"
};
obj.name = "Haha";
interface Info {
readonly name: string;
}
const info: Info = {
name: "Lison"
};
info["name"] = "Haha"; // Cannot assign to 'name' because it is a read-only property
6. 函数类型
接口可以描述普通对象,还可以描述函数类型,我们先看写法:
interface AddFunc {
(num1: number, num2: number): number;
}
这里我们定义了一个AddFunc结构,这个结构要求实现这个结构的值,必须包含一个和结构里定义的函数一样参数、一样返回值的方法,或者这个值就是符合这个函数要求的函数。我们管花括号里包着的内容为调用签名,它由带有参数类型的参数列表和返回值类型组成。后面学到类型别名一节时我们还会学习其他写法。来看下如何使用:
const add: AddFunc = (n1, n2) => n1 + n2;
const join: AddFunc = (n1, n2) => ${n1} ${n2}; // 不能将类型'string'分配给类型'number'
add("a", 2); // 类型'string'的参数不能赋给类型'number'的参数
上面我们定义的add函数接收两个数值类型的参数,返回的结果也是数值类型,所以没有问题。而join函数参数类型没错,但是返回的是字符串,所以会报错。而当我们调用add函数时,传入的参数如果和接口定义的类型不一致,也会报错。
你应该注意到了,实际定义函数的时候,名字是无需和接口中参数名相同的,只需要位置对应即可。
四、Interface 与 Type 的区别
1. 区别
- 接口可以重复定义的接口类型,它的属性会叠加,类型别名不行
interface Language {
id: number
}
interface Language {
name: string
}
let lang: Language = {
id: 1, // ok
name: 'name', // ok
}
// 如果使用类型别名
/** ts(2300) 重复的标志 */
type Language = {
id: number
}
/** ts(2300) 重复的标志 */
type Language = {
name: string
}
let lang: Language = {
id: 1,
name: 'name',
}
- type 可以使用联合类型和交集,interface 不能使用联合类型和交集组合
type Pet = Dog | Cat
// 具体定义数组每个位置的类型
type PetList = [Dog, Pet]
- type 支持类型映射,interface不支持
type Keys = "firstname" | "surname"
type DudeType = {
[key in Keys]: string
}
const test: DudeType = {
firstname: "Pawel",
surname: "Grzybek"
}
// 报错
//interface DudeType {
// [key in keys]: string
//}
2. 相同点
都允许拓展(extends)
interface 和 type 都可以拓展,并且两者并不是相互独立的,也就是说 interface 可以 extends type, type 也可以 extends interface , 虽然效果差不多,但是两者语法不同。
- interface extends interface
interface Name {
name: string;
}
interface User extends Name {
age: number;
}
- type extends type
type Name = {
name: string;
}
type User = Name & { age: number };
- interface extends type
type Name = {
name: string;
}
interface User extends Name {
age: number;
}
- type extends interface
interface Name {
name: string;
}
type User = Name & {
age: number;
}
总结:
interface 只能用于定义对象类型和方法,而 type 的声明方式除了对象之外还可以定义交叉、联合、原始类型等,类型声明的方式适用范围显然更加广泛。
但是interface也有其特定的用处:
interface 方式可以实现接口的 extends 和 implements
interface 可以实现接口合并声明