接口
理解接口
就是定义标准,相比抽象类更强大,能规范属性、函数,类。在面向对象编程中,接口的意义在于定义了一种行为和动作的规范,起到限制和规范的作用。ts的接口类型,包括属性,函数,可索引和类,接口扩展等等。
其实说白了,接口就是用代码描述一个对象必须有什么属性(包括方法),至于对象有没有其他属性就不管了,只要接口定义的有就行,没有就报错!
看个简单的例子:
// 传入参数必须是对象,对象属性有类型约束
function printLabel(label: {label: string, size: number}) {
console.log(`${label.label}${label.size}`);
}
var labelJson = {label: 'amoy', size: 99} // 这个对象满足约束条件,没有报错
printLabel(labelJson) // amoy99
复杂一些的例子,其实我们可以把interface理解为要求
// 要求Human的类型和属性
interface Shape {
head: string;
body: string;
}
interface Human {
readonly name: string;
age: number;
shape: Shape;
say(word: string): void; // 属性是个函数
likedgame?: Array<string>; // 喜欢或者什么都不喜欢,可选属性
}
let isaacgao: Human = {
name: 'isaac',
age: 24,
shape: {
head: "⭕️",
body: "正方形"
},
say(word: string) {
console.log(this.name + ' 说 ' + word) // isaac 说 hello world
},
likedgame: ['pokemon', 'monster hunter']
}
isaacgao.say('hello world')
isaacgao.name = 'gao' // Cannot assign to 'name' because it is a read-only property.
还有一个有意思的地方,如果你声明一个interface作为参数,你是通过一个变量传入的,你是可以传递多余interface规定的属性的。但是你不通过变量直接传则会报错。
属性接口
interface fullName { // 对函数传参进行约束,
firstName: string; // 注意 分号结束
lastName: string;
age?: number // 可选属性
}
function printName(name: fullName): string {
return `你的全名是:${name.firstName}${name.lastName}`
}
var parameter = { firstName: '尼古拉斯', lastName: '赵四', age: 25 } // 传参必须包含firstName、lastName,顺序无所谓
console.log(printName(parameter)); // 你的全名是:尼古拉斯赵四
// $.ajax例子
interface ajaxConfig {
type: string;
url: string;
data?: string|null;
dataType: string
}
function ajax(config: ajaxConfig): void {
var xhr = new XMLHttpRequest()
xhr.open(`${config.type}`, config.url, true)
xhr.send(config.data)
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200 || xhr.status === 304) {
console.log('success');
if (config.type === 'json') {
return JSON.parse(xhr.responseText)
} else {
xhr.responseText
}
}
}
}
ajax({
type: 'GET',
url: 'http://a.itying.com/api/productlist',
dataType: 'json',
data: 'name=zhaosi'
})
函数接口
// 注意写法 同样支持批量约束
interface encrypt {
(key: string, val: string): string;
}
var md5: encrypt = function (key: string, val: string): string {
return key+val
}
console.log(md5('isaac', 'kao')); //isaackao
可索引接口(不常用)
可以约束属性和值的类型
// ts中定义数组的方式
var arr1: number[] = [1,23,4,5]
var arr2: Array<number> = [122,33,4,24,23,5423,4]
// 对数组约束
interface userArr {
[index: number]:string // 约束索引类型与值类型
}
var arr: userArr = ['123', 'isaac', 'kao']
console.log(arr[1])
// 对对象约束
interface userObj {
[index: string]: string
// [propName: string]: number // 对象一般这么写
}
var obj: userObj = {name: 'isaac', age: '25'}
class类型接口
和抽象类有点相似,父类定义一个标准,子类实现接口标准
// 有点像属性和方法接口整合到一起
interface Animal {
name: string;
eat(str: string): void;
}
class Horse implements Animal {
public name: string;
constructor(name: string) {
this.name = name
}
eat() { // 可以不传参数,但是方法必须要遵循类接口的定义
console.log(this.name + '吃粮食');
}
}
var d = new Horse('战马')
console.log(d.eat()); //战马吃粮食
class Tiger implements Animal {
public name: string;
constructor(name: string) {
this.name = name
}
eat(food: string) { // 可以不传参数,但是方法必须要遵循类接口的定义
console.log(this.name + food);
}
}
var t = new Tiger('猛虎')
console.log(t.eat('吃人!')); //猛虎吃人!
接口继承
一个interface可以批量继承多个interface,你还可以继承一个已经继承其他interfce的interface(比如Mamel继承了Animal,Human再继承Mamel)
注意,如果继承(包括多重继承)的两个interface有相冲突的属性或类型,会报错!
interface Animal {
move(): void;
}
interface Mamel {
fur: boolean;
pregnancy: boolean;
intelligent: boolean
}
interface Human extends Animal, Mamel { // 人类继承了动物的move方法
name: string;
age: number;
}
let gao: Human {
name: 'hang',
age: 24,
move() {
console.log('在动!')
},
fur: true;
pregnancy: true;
intelligent: true
}
gao.move()
接口扩展
接口可以继承接口
- 接口可以相互继承
- 类不仅可以继承父类,还可以实现接口
{
interface Animal {
eat(): void;
}
interface Person extends Animal { // 接口继承
work(): void;
}
// web 实现Person接口,Person继承了Animal,所以内部有两个方法
class Web implements Person {
public name: string
constructor(name: string) {
this.name = name
}
eat() {
console.log(this.name + '喜欢吃粽子');
}
work() {
console.log(this.name + '在上班!');
}
}
var w = new Web('韩梅梅')
w.work() //韩梅梅在上班!
// 稍微复杂的例子
class programmer {
public name: string
constructor(name: string) {
this.name = name
}
coding(code: string) {
console.log(this.name + '写' + code);
}
}
// web开发者继承程序员 并且 实现Person类的规范(必须有eat和work方法)
class Weber extends programmer implements Person {
constructor(name: string) {
super(name)
}
eat() {
console.log(this.name + '喜欢吃粽子');
}
work() {
console.log(this.name + '在上班!');
}
}
var ww = new Weber('程序员小高')
ww.coding('echo hello world') // 程序员小高写echo hello world
}