TypeScript的接口,个人理解就是一种约束,包括各种类型的契约或者代码定义上的契约。当然,和java中的用法基本一致,接口可以被继承也可以被实现。
interface LabelledValue { label: string; } function printLabel(labelledValue: LabelledValue) { console.log(labelledValue.label); } let myLabel: LabelledValue = {label: 'this is my label'} printLabel(myLabel) // this is my label
注意: 1、可选属性:label?: string; 2、只读属性:readonly label: string;(只允许创建的时候修改一次) readonly和const:变量声明用const,属性声明用readonly
看一个readonly的例子:
interface Point { readonly x: number; readonly y: number; } let p1: Point = {x: 121, y: 78} console.log(p1); // {x: 121, y: 78} p1.x = 22 // wrong!
注意: 如果是只读型数组,请使用ReadonlyArray
interface SquareConfig { color?: string; width?: number; [propName: string]: any; // 代表任意属性,其中key类型为string,value类型为any任意 }
接口可以描述js对象中拥有的各种外形。比如如下可以描述js对象具有函数类型:
interface SearchFunc { (source: string, subString: string): boolean; } let mySearch: SearchFunc; mySearch = function(src, sub) { // ts会自动识别参数类型,参数名可以不一致 let result = src.search(sub); return result > -1; }
其中,source、subString均为string型入参,boolean类型为出参。
接口描述这种类型,比较有意思,可索引的类型包含两种,一种是对象,一种的数组。可以在接口中描述索引的类型,以及索引值的类型,如下:
interface StringArray { [index: number]: string; } let z1: StringArray = {1: "awdawd"} let z2: StringArray = ['admin'] console.log(z1, z2); // { '1': 'awdawd' } [ 'admin' ]
如上接口,可以被数组实现,也可以被对象实现。索引签名除了number还要string,可以同时使用两种类型的索引。但是要注意:数字类型索引的索引值一定要是字符串索引类型索引值的子类型。举个例子:
class Animal { name: string; } class Dog extends Animal { breed: string; } // 错误:使用'string'索引,有时会得到Animal! interface NotOkay { [x: number]: Animal; [x: string]: Dog; }
说明,按照意思是number索引类型是Animal,string索引类型是Dog,Animal必须是Dog的子类型,但是实际恰恰相反——Dog是Animal类型的子类型,所以这里会报错。因为当使用number作索引时,js会将它转换为string,然后再去索引。所以必须保证number索引是string索引的子类型,否则会造成索引值混乱。
使用索引签名实现ReadonlyArray效果:
interface ReadonlyStringArray { readonly [index: number]: string; } let myArray: ReadonlyStringArray = ["Alice", "Bob"]; myArray[2] = "Mallory"; // error!
在java里面,接口生来就是被实现的,就好像抽象对象生来就是要被继承一样。
interface ClockInterface { // 定义接口,包含属性currentTime,所有该接口的实现必须包含该字段 currentTime: Date; } class Clock implements ClockInterface{ currentTime: Date; // 该字段必须包含 constructor(h: number, m: number){}; }
同样地,在接口里面可以再加函数约束,所有实现必须重写该函数:
interface ClockInterface { // 定义接口,包含属性currentTime,所有该接口的实现必须包含该字段 currentTime: Date; setTime(d: Date); } class Clock implements ClockInterface{ currentTime: Date; // 该字段必须包含 setTime(d: Date) { this.currentTime = d; } constructor(h: number, m: number){}; }
接口和类相似,彼此之间是可以相互继承的,使用关键字extend实现:
interface Shape { color: string; } interface Square extends Shape { sideLength: number; } let square = <Square>{}; // 断言,同:{} as Square square.color = "blue"; square.sideLength = 10; // { color: 'blue', sideLength: 10 }
这里,Shape接口被Square接口所继承,所以自然Square接口多了一个属性color。
有时期望使用接口同时描述对象的属性、方法等,可以如下:
interface Counter { (start: number): string; interval: number; reset(): void; } function getCounter(): Counter { let counter = <Counter>function (start: number) { }; counter.interval = 123; counter.reset = function () { }; return counter; } let c = getCounter(); c(10); c.reset(); c.interval = 5.0;
本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。
我来说两句