TypeScript入门五:TypeScript的接口
<ul style="color: rgba(41, 78, 128, 1)"><li>TypeScript接口的基本使用</li>
<li>TypeScript函数类型接口</li>
<li>TypeScript可索引类型接口</li>
<li>TypeScript类类型接口</li>
<li>TypeScript接口与继承</li>
</ul>
<h2 style="background-color: rgba(41, 78, 128, 1); border-radius: 5px"> 一、TypeScript接口的基本使用</h2>
<p>1.1定义TypeScript接口的指令(<span style="color: rgba(0, 0, 255, 1)">interface</span>)</p>
<p>接口让我们想到的第一个短语就是(API)。比如日常我们所说的调用某某程序的API一般都是跨应用的接口,如别的网站的或者APP的接口;还有我们每天都是用的编程语言的指令和内置的方法及属性,这些可以叫做编程语言的接口;还有令我们既爱又恨的各种平台、框架、库的庞大接口集,特别是这些东西每一次升级都会产生新的接口或者修改以前的接口,这些接口需要我们付出大量的学习时间。</p>
<p>而学习接口第一要务就是学习接口的语法,这些语法往往定义了各种读写规则,这里抛开接口背后实现的意义不谈,因为学习使用TypeScript接口主要就是学会如何自定义各种接口的规则,至于你将来要在程序中定义什么样的接口、根据什么定义接口规则都是要根据程序本身的性质决定的。</p>
<p>比如按照我们JS的形式给一个函数定义参数接口:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)">1</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> printLabel(labelledObj: { label: string }) {
</span><span style="color: rgba(0, 128, 128, 1)">2</span> <span style="color: rgba(0, 0, 0, 1)">console.log(labelledObj.label);
</span><span style="color: rgba(0, 128, 128, 1)">3</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">4</span> let myObj = { size: 10, label: "Size 10 Object"<span style="color: rgba(0, 0, 0, 1)"> };
</span><span style="color: rgba(0, 128, 128, 1)">5</span> printLabel(myObj);</pre>
</div>
<p>这里会有类型检查帮助我们检查传入(printLabel)函数的参数是否有指定的属性(label)。然后,来看看TypeScript接口如何定义上面这个参数接口:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">interface LabelledValue {
label: string;
}
</span><span style="color: rgba(0, 0, 255, 1)">function</span> printLabel(labelledObj: LabelledValue) {<span style="color: rgba(0, 128, 0, 1)">//这里指定参数要符合LabelledValue接口规则,参数不许包含一个label属性,且类型为string
</span><span style="color: rgba(0, 0, 0, 1)">console.log(labelledObj.label);
}
let myObj </span>= {size: 10, label: "Size 10 Object"<span style="color: rgba(0, 0, 0, 1)">};
printLabel(myObj);</span></pre>
</div>
<p>感觉这两种实现方式没有什么区别,但是对于严格TypeScript的接口来说就没有这门宽松了,TypeScript包含非常丰富的接口规则,定义TypeScript接口最基本的规则就有:可选属性、只读属性、额外属性检查。</p>
<p><span style="color: rgba(0, 0, 255, 1)">1.2可选属性(option bags模式):在可选属性名称定义的后面加上(?)问号。注意使用可选属性后,就不能出现额外的属性了,除非使用后面的额外属性检查规则实现。</span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 0, 0, 1)">interface SquareConfig {
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span> color?: string;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">定义为接口的额外属性</span>
<span style="color: rgba(0, 128, 128, 1)"> 3</span> width?: number;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">定义为接口的额外属性</span>
<span style="color: rgba(0, 128, 128, 1)"> 4</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> createSquare(config: SquareConfig): {color: string; area: number} {
</span><span style="color: rgba(0, 128, 128, 1)"> 6</span> let newSquare = {color: "white", area: 100<span style="color: rgba(0, 0, 0, 1)">};
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span> <span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (config.color) {
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span> newSquare.color =<span style="color: rgba(0, 0, 0, 1)"> config.color;
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">10</span> <span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (config.width) {
</span><span style="color: rgba(0, 128, 128, 1)">11</span> newSquare.area = config.width *<span style="color: rgba(0, 0, 0, 1)"> config.width;
</span><span style="color: rgba(0, 128, 128, 1)">12</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">13</span> <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> newSquare;
</span><span style="color: rgba(0, 128, 128, 1)">14</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">15</span> let mySquare = createSquare({color: "black"} );<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">可选择传入部分可选属性</span>
<span style="color: rgba(0, 128, 128, 1)">16</span> let mySquare1 = createSquare({color: "black",width:120<span style="color: rgba(0, 0, 0, 1)">} );
</span><span style="color: rgba(0, 128, 128, 1)">17</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> let mySquare2 = createSquare({color: "black",widtg:120} );//不能出现属性名不一致,这同样被识别为额外属性,出现2345错误</span>
<span style="color: rgba(0, 128, 128, 1)">18</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> let mySquare3 = createSquare({color: "black",width:120,size:120} );//这里出现了一个额外属性size,会出现2345错误</span></pre>
</div>
<p><span style="color: rgba(0, 0, 255, 1)">1.3只读属性:实现只读属性接口时不能不写只读属性,并且也不能出现额外属性,除非使用额外属性检查。</span></p>
<p>readonly(指定属性只读):在接口类型中指定的属性前面添加readonly修饰符来指定该属性为指定。</p>
<p>ReadonlyArray<T>(定义只读数组):定义只读数组类型结构的接口直接使用ReadonlyArray<T>类型来定义就可以了,不需要使用<span style="color: rgba(0, 0, 255, 1)">interface</span>关键字。在官方文档中提到了ReadonlyArray<T>的底层实现就是将数组的可变方法去掉了。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">readonly</span>
<span style="color: rgba(0, 128, 128, 1)"> 2</span> <span style="color: rgba(0, 0, 0, 1)">interface Point {
</span><span style="color: rgba(0, 128, 128, 1)"> 3</span> <span style="color: rgba(0, 0, 0, 1)">readonly x: number;
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span> <span style="color: rgba(0, 0, 0, 1)">readonly y: number;
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)"> 6</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> fun(p:Point):number{
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span> <span style="color: rgba(0, 0, 255, 1)">return</span> p.x +<span style="color: rgba(0, 0, 0, 1)"> p.y;
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span> fun({x:1,y:2<span style="color: rgba(0, 0, 0, 1)">})
</span><span style="color: rgba(0, 128, 128, 1)">10</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> fun({x:1})//只读属性必须全部写入参数</span>
<span style="color: rgba(0, 128, 128, 1)">11</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> fun({x:1,y:2,z:3})//不能添加额外的属性</span>
<span style="color: rgba(0, 128, 128, 1)">12</span> fun({x:1,y:2,z:3} as Point)<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">这里使用了额外属性检查就不会报错</span>
<span style="color: rgba(0, 128, 128, 1)">13</span>
<span style="color: rgba(0, 128, 128, 1)">14</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">ReadonlyArray<T>定义只读数组</span>
<span style="color: rgba(0, 128, 128, 1)">15</span> let a:number[] = ;
</span><span style="color: rgba(0, 128, 128, 1)">16</span> let ro:ReadonlyArray<number> =<span style="color: rgba(0, 0, 0, 1)"> a;
</span><span style="color: rgba(0, 128, 128, 1)">17</span> let ro1:ReadonlyArray<number> = ;
</span><span style="color: rgba(0, 128, 128, 1)">18</span> console.log(ro ==<span style="color: rgba(0, 0, 0, 1)"> ro1);
</span><span style="color: rgba(0, 128, 128, 1)">19</span> ro1 =<span style="color: rgba(0, 0, 0, 1)"> a;
</span><span style="color: rgba(0, 128, 128, 1)">20</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> a = ro; //number[] 类型不等于ReadonlyArray<T> ,这是变量类型那不内容的延伸了,TypeScript对变量的类型有严格的要求</span>
<span style="color: rgba(0, 128, 128, 1)">21</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> a = ro1;//同上</span>
<span style="color: rgba(0, 128, 128, 1)">22</span> a = ro as number[];<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">可以使用断言重写ro来实现类型转换</span>
<span style="color: rgba(0, 128, 128, 1)">23</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ro = 100;//只读数组不能重写元素值</span></pre>
</div>
<p>1.4额外属性检查:在前面的可选属性和只读属性都提到了额外属性检查,额外属性检查顾名思义就是接口中出现了额外的属性,而当在接口中定义可选和只读规则以后就不能出现额外属性,但是有时候在一些实现中可能出现额外属性就可以使用额外属性检查来实现。</p>
<p><span style="color: rgba(0, 0, 255, 1)">额外属性检查就是在实现接口时使用“as”来告诉编译环境,这里允许出现额外属性,只要除额外属性以外的其他属性符合接口的规则就允许实现。</span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)">1</span> <span style="color: rgba(0, 0, 0, 1)">interface SquareConfig {
</span><span style="color: rgba(0, 128, 128, 1)">2</span> color?<span style="color: rgba(0, 0, 0, 1)">: string;
</span><span style="color: rgba(0, 128, 128, 1)">3</span> width?<span style="color: rgba(0, 0, 0, 1)">: number;
</span><span style="color: rgba(0, 128, 128, 1)">4</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">5</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> createSquare(config: SquareConfig): { color: string; area: number } {
</span><span style="color: rgba(0, 128, 128, 1)">6</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ...</span>
<span style="color: rgba(0, 128, 128, 1)">7</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">8</span> let mySquare = createSquare({ colour: "red", width: 100 });<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">这里不小心把color写成了colour,colour被识别为额外属性了</span>
<span style="color: rgba(0, 128, 128, 1)">9</span> let mySquare1 = createSquare({ colour: "red", width: 100 } as SquareConfig);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">使用额外属性检查就可以解决这类报错</span></pre>
</div>
<p>关于额外属性检查,看是可以用来解决一些问题,实际上也确实可以解决一些问题,但是就上面的例子来说,这并不是一个好的结局方案,因为我们期望的时传入color的属性值,但是由于编码失误写错了单词,额外属性帮我们静默了这个错误,也同时让我们的程序偏离了我们期望的方向。关于这样的问题后面有一种索引签名的方式来解决,也就是后面的可索引的类型。</p>
<h2 style="background-color: rgba(41, 78, 128, 1); border-radius: 5px"> 二、TypeScript函数类型接口</h2>
<p>在TypeScript函数部分介绍了使用type定义Ts函数类型(详细可以了解官方文档或者这篇博客:TypeScript入门三:TypeScript函数类型),TypeScript接口也可以定义函数的接口类型,定义模式与type定义函数类型非常类似。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> type myAdd = (baseValue: number, increment: number) =><span style="color: rgba(0, 0, 0, 1)"> number;
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span> <span style="color: rgba(0, 0, 0, 1)">interface inAdd {
</span><span style="color: rgba(0, 128, 128, 1)"> 3</span> <span style="color: rgba(0, 0, 0, 1)">(baseValue: number, increment: number):number;
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">根据函数类型和接口声明函数变量</span>
<span style="color: rgba(0, 128, 128, 1)"> 6</span> let myAdd1:myAdd = <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(x:number,y:number) : number{
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span> <span style="color: rgba(0, 0, 255, 1)">return</span> x +<span style="color: rgba(0, 0, 0, 1)"> y;
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span> let myAdd2:inAdd = <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(x:number,y:number) : number{
</span><span style="color: rgba(0, 128, 128, 1)">10</span> <span style="color: rgba(0, 0, 255, 1)">return</span> x -<span style="color: rgba(0, 0, 0, 1)"> y;
</span><span style="color: rgba(0, 128, 128, 1)">11</span> }</pre>
</div>
<p>函数实现函数接口和函数类的实例化都一样,其都属于函数内部语法,比如可以设置参数默认值;参数名称与函数类或者接口定义的可以不一致,只要参数对应的位置实现的参数类型一致就可以了。</p>
<h2 style="background-color: rgba(41, 78, 128, 1); border-radius: 5px"> 三、TypeScript可索引类型接口</h2>
<p>在前面的额外属性检查中就提到了可索引类型接口,并有说过可以通过可索引类型接口解决由于书写错误,并由额外属性导致的错误静默问题。先来了解可索引接口规则是什么?再看看如何解决前面的问题。</p>
<p><span style="color: rgba(0, 0, 255, 1)">3.1数字索引的可索引类型接口:数字可索引类型其实本质上就是定义个数组类型,只要赋值符合该接口的定义就可以直接赋值。</span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)">1</span> <span style="color: rgba(0, 0, 0, 1)">interface StringArray {
</span><span style="color: rgba(0, 128, 128, 1)">2</span> <span style="color: rgba(0, 0, 0, 1)">: string;
</span><span style="color: rgba(0, 128, 128, 1)">3</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">4</span>
<span style="color: rgba(0, 128, 128, 1)">5</span> <span style="color: rgba(0, 0, 0, 1)">let myArray: StringArray;
</span><span style="color: rgba(0, 128, 128, 1)">6</span> myArray = ["Bob", "Fred"<span style="color: rgba(0, 0, 0, 1)">];
</span><span style="color: rgba(0, 128, 128, 1)">7</span> let a = ["1","2","3"<span style="color: rgba(0, 0, 0, 1)">];
</span><span style="color: rgba(0, 128, 128, 1)">8</span> myArray = a;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">这里并不会失败,数字可索引类型其实本质上就是定义个数组类型,只要赋值符合该接口的定义就可以直接赋值</span>
<span style="color: rgba(0, 128, 128, 1)">9</span> let myStr: string = myArray;</pre>
</div>
<p> <span style="color: rgba(0, 0, 255, 1)">3.2字符串可索引类型接口:字符串可索引类型其本质就是定义对象类型,只要赋值符合该接口定义就可以直接赋值。</span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)">1</span> <span style="color: rgba(0, 0, 0, 1)">interface StringObject {
</span><span style="color: rgba(0, 128, 128, 1)">2</span> <span style="color: rgba(0, 0, 0, 1)">:string
</span><span style="color: rgba(0, 128, 128, 1)">3</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">4</span> let myObj : StringObject =<span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)">5</span> 'name':'他乡踏雪'<span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)">6</span> 'professional':'Web front end'
<span style="color: rgba(0, 128, 128, 1)">7</span> }</pre>
</div>
<p><span style="color: rgba(0, 0, 255, 1)">3.3字符串和数字两种索引签名组合使用:</span></p>
<p>这种复杂的接口应用在官方文档中只给出了一个引导性的示例,官方使用了文字描述使用方法,而示例只给出了错误使用提示,并没有给完整的正确示例,估计这让很多初学者比较头疼,我这两天到各个教程中寻找完整的正确示例,但都没有找到,最后通过n次测试终于实现了两种索引组合使用的正确示例。直接上代码,<span style="color: rgba(0, 0, 255, 1)">在代码的注释中解析这种接口实现的规则:</span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 0, 0, 1)">class Animal {
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">定义类作为接口索引指向的值时:</span>
<span style="color: rgba(0, 128, 128, 1)"> 3</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 类内部的成员必须初始化赋值或者基于构造函数实例化赋值</span>
<span style="color: rgba(0, 128, 128, 1)"> 4</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 这里我采用了构造函数实例化赋值</span>
<span style="color: rgba(0, 128, 128, 1)"> 5</span> <span style="color: rgba(0, 0, 0, 1)">name: string;
</span><span style="color: rgba(0, 128, 128, 1)"> 6</span> <span style="color: rgba(0, 0, 0, 1)">constructor(nameStr:string){
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span> <span style="color: rgba(0, 0, 255, 1)">this</span>.name =<span style="color: rgba(0, 0, 0, 1)"> nameStr;
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">10</span> <span style="color: rgba(0, 0, 0, 1)">class Dog extends Animal {
</span><span style="color: rgba(0, 128, 128, 1)">11</span> <span style="color: rgba(0, 0, 0, 1)">breed: string;
</span><span style="color: rgba(0, 128, 128, 1)">12</span> <span style="color: rgba(0, 0, 0, 1)">constructor(breedStr:string,nameStr:string){
</span><span style="color: rgba(0, 128, 128, 1)">13</span> <span style="color: rgba(0, 0, 0, 1)"> super(nameStr);
</span><span style="color: rgba(0, 128, 128, 1)">14</span> <span style="color: rgba(0, 0, 255, 1)">this</span>.breed =<span style="color: rgba(0, 0, 0, 1)"> breedStr;
</span><span style="color: rgba(0, 128, 128, 1)">15</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">16</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">17</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 数字和字符串索引签名组合使用时:</span>
<span style="color: rgba(0, 128, 128, 1)">18</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 数字索引赋值类型必须是字符串索引赋值类型的子类型</span>
<span style="color: rgba(0, 128, 128, 1)">19</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 这个示例中数字索引赋值的Dog类型就是字符串索引赋值的Animal的子类型</span>
<span style="color: rgba(0, 128, 128, 1)">20</span>
<span style="color: rgba(0, 128, 128, 1)">21</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">接口中定义索引时索引签名的类型是关键,</span>
<span style="color: rgba(0, 128, 128, 1)">22</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 索引定义的标识名称(示例中的‘x’)并不重要,</span>
<span style="color: rgba(0, 128, 128, 1)">23</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 可以使用任何合法字符,我没有测试过特殊字符,</span>
<span style="color: rgba(0, 128, 128, 1)">24</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 但实际上它是无意意义的,比如示例中两个x可以替换成x和y照样不影响接口实现</span>
<span style="color: rgba(0, 128, 128, 1)">25</span> <span style="color: rgba(0, 0, 0, 1)">interface animals {
</span><span style="color: rgba(0, 128, 128, 1)">26</span> <span style="color: rgba(0, 0, 0, 1)">: Dog;
</span><span style="color: rgba(0, 128, 128, 1)">27</span> <span style="color: rgba(0, 0, 0, 1)">: Animal;
</span><span style="color: rgba(0, 128, 128, 1)">28</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">29</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">基于数字与字符串索引组合的接口实现,</span>
<span style="color: rgba(0, 128, 128, 1)">30</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 使用{}定义成对象类型</span>
<span style="color: rgba(0, 128, 128, 1)">31</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 不能使用[]只实现数字索引的值</span>
<span style="color: rgba(0, 128, 128, 1)">32</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 但可以使用{}只实现字符串索引的值</span>
<span style="color: rgba(0, 128, 128, 1)">33</span> let myAnimals : animals =<span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 128, 1)">34</span> 1:<span style="color: rgba(0, 0, 255, 1)">new</span> Dog('Dog1','animal1'<span style="color: rgba(0, 0, 0, 1)">),
</span><span style="color: rgba(0, 128, 128, 1)">35</span> '2':<span style="color: rgba(0, 0, 255, 1)">new</span> Dog('Dog2','animal2'<span style="color: rgba(0, 0, 0, 1)">),
</span><span style="color: rgba(0, 128, 128, 1)">36</span> 'animal1':<span style="color: rgba(0, 0, 255, 1)">new</span> Animal('animal1'<span style="color: rgba(0, 0, 0, 1)">),
</span><span style="color: rgba(0, 128, 128, 1)">37</span> 'animal2':<span style="color: rgba(0, 0, 255, 1)">new</span> Animal('animal2'<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">38</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">39</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> let myAnimals1 : animals = ;//报错</span>
<span style="color: rgba(0, 128, 128, 1)">40</span> let myAnimals2 : animals = { <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">这里不报错</span>
<span style="color: rgba(0, 128, 128, 1)">41</span> 'animal1':<span style="color: rgba(0, 0, 255, 1)">new</span> Animal('animal1'<span style="color: rgba(0, 0, 0, 1)">),
</span><span style="color: rgba(0, 128, 128, 1)">42</span> 'animal2':<span style="color: rgba(0, 0, 255, 1)">new</span> Animal('animal2'<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">43</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">44</span>
<span style="color: rgba(0, 128, 128, 1)">45</span> console.log(myAnimals);</pre>
</div>
<p>在可索引类型类型接口中照样可以使用只读属性规则:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)">1</span> <span style="color: rgba(0, 0, 0, 1)">interface ReadonlyStringArray {
</span><span style="color: rgba(0, 128, 128, 1)">2</span> <span style="color: rgba(0, 0, 0, 1)"> readonly : string;
</span><span style="color: rgba(0, 128, 128, 1)">3</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">4</span> let myArray: ReadonlyStringArray = ["Alice", "Bob"<span style="color: rgba(0, 0, 0, 1)">];
</span><span style="color: rgba(0, 128, 128, 1)">5</span> myArray = "Mallory"; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> error!</span></pre>
</div>
<p>前面说要基于可索引类型接口展示一个解决额外属性产生的潜在问题,写到这里我感觉好像没有多大必要了,如果你真的搞懂了可索引类型接口规则,应该很轻松想到它可以如何实现,还有考虑到篇幅问题,就不在这里展示了,如果有需要可以在评论区留言。</p>
<h2 style="background-color: rgba(41, 78, 128, 1); border-radius: 5px"> 四、TypeScript类类型接口</h2>
<p>TypeScript类类型接口与抽象类非常类型,都是用来定义类的必须结构,但是类类型接口与抽象类还是有些区别,抽象类中可以实现具体的细节,但是在类类型接口中不能实现具体的细节。比如在抽象类中可以直接实现方法的具体内容,但是在类类型接口只能声明一个方法的类型(包括名称、参数类型、返回值类型),但不能在类类型接口中直接实现函数体的具体内容。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 0, 0, 1)">interface ClockInterface {
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span> currentTime: Date;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">指定强制实现的公共成员,在接口实现中必须初始化或者在构造其中赋值</span>
<span style="color: rgba(0, 128, 128, 1)"> 3</span> setTime(d: Date):<span style="color: rgba(0, 0, 255, 1)">void</span>;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">指定强制实现的函数,在接口实现中必须实现,之一这里定义时需要有指定的返回值类型,void表示没有任何类型,也就是不返任何类型的回值</span>
<span style="color: rgba(0, 128, 128, 1)"> 4</span>
<span style="color: rgba(0, 128, 128, 1)"> 5</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)"> 6</span>
<span style="color: rgba(0, 128, 128, 1)"> 7</span> <span style="color: rgba(0, 0, 0, 1)">class Clock implements ClockInterface {
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span> <span style="color: rgba(0, 0, 0, 1)">currentTime: Date;
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">↑上面这里第一种是想方法:实现接口强制约定要实现的公共成员currentTime,在构造器中赋值实现</span>
<span style="color: rgba(0, 128, 128, 1)">10</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">↓ 下面这里第二种实现方法: 实现接口强制约定要实现的公共成员currentTime,初始化值的方式实现</span>
<span style="color: rgba(0, 128, 128, 1)">11</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> currentTime: Date = new Date();</span>
<span style="color: rgba(0, 128, 128, 1)">12</span>
<span style="color: rgba(0, 128, 128, 1)">13</span> setTime(d: Date) {<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">函数默认不返回任何类型的值,默认值为undefined,但它不是undefined类型</span>
<span style="color: rgba(0, 128, 128, 1)">14</span> <span style="color: rgba(0, 0, 255, 1)">this</span>.currentTime =<span style="color: rgba(0, 0, 0, 1)"> d;
</span><span style="color: rgba(0, 128, 128, 1)">15</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">16</span> <span style="color: rgba(0, 0, 0, 1)">constructor(h: number, m: number) {
</span><span style="color: rgba(0, 128, 128, 1)">17</span> <span style="color: rgba(0, 0, 255, 1)">this</span>.currentTime = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Date();
</span><span style="color: rgba(0, 128, 128, 1)">18</span> <span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(0, 128, 128, 1)">19</span> }</pre>
</div>
<p>关于类类型接口与抽象类的区别还有:</p>
<p>增加其他内容与否:派生类实现抽象类时不能随意增加其他内容,一切根据抽象类定义的结构实现,但是在类类型接口的具体实现中可以增加类类型接口中没有定义的内容。</p>
<p>公共成员与私有成员:抽象类中可以实现公共成员,也可以实现私有成员。但是,类类型接口中非静态成员都是公共公共成员,而且并不需要public修饰,自动被默认为公共成员。</p>
<p>静态成员在抽象类和类类型接口中都可以直接使用static修饰符来定义。</p>
<p>上面都是关于修饰符的相关内容,还有一个问题就是类类接口中不能直接定义构造函数的相关构造结构,在官方文档中描述为类的静态部分,也就常说的constructor函数。而当对一个类类型接口做具体实现时,只会对类类型的实体部分进行检查,而不会对静态部分检查。</p>
<p>而且定义类类型接口时并不能直接使用constructor在类类型接口中定义相关结构,IDE会直接提示错误信息,官方给出的解决方案时使用构造器签名的方式来实现。具体的实现方案就是定义一个构造器签名的类类型接口、定义一个实体部分的类类型接口、然后在根据这两个类类接口的结构的具体实现写在一个类中,这个类的implements指向实体部分的类类型接口、最后定一个实例化工具方法,将方法的第一个参数类型设定为构造器签名的类类型接口类型,实现构造需要的参数跟着写后面,然后指定这个方法的返回类型为实体部分的类类型接口类型,方法内直接返回第一个参数的实例化,实例化时传入对应需要的实例化参数。</p>
<p>具体见下面这个官方文档中的示例,对照下面的注释应该很清晰了:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> interface ClockConstructor {<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">定义构造器签名的类类型接口:作为类类型接口的构造函数的结构</span>
<span style="color: rgba(0, 128, 128, 1)"> 2</span> <span style="color: rgba(0, 0, 255, 1)">new</span> (hour: number, minute: number): ClockInterface;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">构造函数的方法值设定为类类型主体类型</span>
<span style="color: rgba(0, 128, 128, 1)"> 3</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span> interface ClockInterface {<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">定义类类型接口的实体</span>
<span style="color: rgba(0, 128, 128, 1)"> 5</span> tick():<span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)"> 6</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">定义一个类类型接口实现的实例化工具方法,设置参数有:将类类型实现的类的类型设置为构造签名的类类型接口类型,以及构造器需要的参数</span>
<span style="color: rgba(0, 128, 128, 1)"> 8</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 返回值类型设置为类类型接口实体类型</span>
<span style="color: rgba(0, 128, 128, 1)"> 9</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> createClock(ctor: ClockConstructor, hour: number, minute: number): ClockInterface {
</span><span style="color: rgba(0, 128, 128, 1)">10</span> <span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span> ctor(hour, minute);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">内部直接通过类类型的具体实现类实例化并返回即可</span>
<span style="color: rgba(0, 128, 128, 1)">11</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">12</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">类类型接口的具体实现,implements指向类类型接口的实体类型</span>
<span style="color: rgba(0, 128, 128, 1)">13</span> <span style="color: rgba(0, 0, 0, 1)">class DigitalClock implements ClockInterface {
</span><span style="color: rgba(0, 128, 128, 1)">14</span> constructor(h: number, m: number) { }<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">内部构造函数根据定义的构造器签名的类类型接口结构实现</span>
<span style="color: rgba(0, 128, 128, 1)">15</span> <span style="color: rgba(0, 0, 0, 1)">tick() {
</span><span style="color: rgba(0, 128, 128, 1)">16</span> console.log("beep beep"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">17</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">18</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">19</span> <span style="color: rgba(0, 0, 0, 1)">class AnalogClock implements ClockInterface {
</span><span style="color: rgba(0, 128, 128, 1)">20</span> <span style="color: rgba(0, 0, 0, 1)">constructor(h: number, m: number) { }
</span><span style="color: rgba(0, 128, 128, 1)">21</span> <span style="color: rgba(0, 0, 0, 1)">tick() {
</span><span style="color: rgba(0, 128, 128, 1)">22</span> console.log("tick tock"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">23</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">24</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">25</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">将类类型接口的具体实现类作为参数以及构造函数需要的参数一并传入,实例化类类型接口具体实现的类</span>
<span style="color: rgba(0, 128, 128, 1)">26</span> let digital = createClock(DigitalClock, 12, 17<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">27</span> let analog = createClock(AnalogClock, 7, 32);</pre>
</div>
<h2 style="background-color: rgba(41, 78, 128, 1); border-radius: 5px"> 五、TypeScript接口与继承</h2>
<p>接口继承与类继承没什么差异,通过继承可以将被继承的接口内容复制过来,通过继承可以更灵活的将接口分割重用,这里我就直接复制官方文档的一个示例代码展示了,因为从接口语法角度来说非常简单,但是如果要使用上面类类型接口那样的复杂接口来继承另当别论。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 0, 0, 1)">interface Shape {
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span> <span style="color: rgba(0, 0, 0, 1)"> color: string;
</span><span style="color: rgba(0, 128, 128, 1)"> 3</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span>
<span style="color: rgba(0, 128, 128, 1)"> 5</span> <span style="color: rgba(0, 0, 0, 1)">interface PenStroke {
</span><span style="color: rgba(0, 128, 128, 1)"> 6</span> <span style="color: rgba(0, 0, 0, 1)"> penWidth: number;
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span>
<span style="color: rgba(0, 128, 128, 1)"> 9</span> <span style="color: rgba(0, 0, 0, 1)">interface Square extends Shape, PenStroke {
</span><span style="color: rgba(0, 128, 128, 1)">10</span> <span style="color: rgba(0, 0, 0, 1)"> sideLength: number;
</span><span style="color: rgba(0, 128, 128, 1)">11</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">12</span>
<span style="color: rgba(0, 128, 128, 1)">13</span> let square = <Square><span style="color: rgba(0, 0, 0, 1)">{};
</span><span style="color: rgba(0, 128, 128, 1)">14</span> square.color = "blue"<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">15</span> square.sideLength = 10<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">16</span> square.penWidth = 5.0;</pre>
</div>
<p><span style="color: rgba(0, 0, 255, 1)">接口实现混合类型(函数类型与函数对象的静态方法接口)</span>:</p>
<p>在前面已经介绍了关于函数类型接口的实现,但是仅仅只能实现一个单独的函数,在JS中函数本身就是一个对象,在函数对象上实现静态的工具方法是比较常见的现象,TypeScript定义函数类型接口并一同定义一些工具方法也可以实现,这有点像是继承加手动解构的模式,官方文档中的示例也是比较清晰易懂的,还是添加一些注释的方式解析吧。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 0, 0, 1)">interface Counter {
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span> (start: number): string;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">定义函数接口的主体部分</span>
<span style="color: rgba(0, 128, 128, 1)"> 3</span> interval: number;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">定义函数的静态属性接口</span>
<span style="color: rgba(0, 128, 128, 1)"> 4</span> reset(): <span style="color: rgba(0, 0, 255, 1)">void</span>;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">定义函数的静态方法接口</span>
<span style="color: rgba(0, 128, 128, 1)"> 5</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)"> 6</span>
<span style="color: rgba(0, 128, 128, 1)"> 7</span> <span style="color: rgba(0, 0, 255, 1)">function</span> getCounter(): Counter {<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">这里可以说是继承,或许它更像时通过接口定义函数的类型(它真正的含义是标识这个方法返回的值是该接口类型)</span>
<span style="color: rgba(0, 128, 128, 1)"> 8</span> let counter = <Counter><span style="color: rgba(0, 0, 255, 1)">function</span> (start: number) { };<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">通过<接口名称>获取函数主体部分,并赋给一个变量(实际上这个变量才是真正实现接口的函数类型对象)</span>
<span style="color: rgba(0, 128, 128, 1)"> 9</span> counter.interval = 123;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">直接在函数对象上实现接口中定义的静态属性</span>
<span style="color: rgba(0, 128, 128, 1)">10</span> counter.reset = <span style="color: rgba(0, 0, 255, 1)">function</span> () { };<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">直接在函数对象上实现接口中定义的静态方法</span>
<span style="color: rgba(0, 128, 128, 1)">11</span> <span style="color: rgba(0, 0, 255, 1)">return</span> counter;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">返回这个被实现的函数</span>
<span style="color: rgba(0, 128, 128, 1)">12</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">13</span>
<span style="color: rgba(0, 128, 128, 1)">14</span> let c =<span style="color: rgba(0, 0, 0, 1)"> getCounter();
</span><span style="color: rgba(0, 128, 128, 1)">15</span> c(10<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">16</span> <span style="color: rgba(0, 0, 0, 1)">c.reset();
</span><span style="color: rgba(0, 128, 128, 1)">17</span> c.interval = 5.0;</pre>
</div>
<p><span style="color: rgba(0, 0, 255, 1)">接口继承类:</span></p>
<p>当接口继承了一个类类型时,它会继承类的成员但不包括其实现。 就好像接口声明了所有类中存在的成员,但并没有提供具体实现一样。 接口同样会继承到类的private和protected成员。</p>
<p>在实现这类接口的时候必须要同时实现继承该接口继承的类,或者继承该接口继承的类的子类,比如示例:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 0, 0, 1)">class Control {
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span> <span style="color: rgba(0, 0, 0, 1)">private state: any;
</span><span style="color: rgba(0, 128, 128, 1)"> 3</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span>
<span style="color: rgba(0, 128, 128, 1)"> 5</span> <span style="color: rgba(0, 0, 0, 1)">interface SelectableControl extends Control {
</span><span style="color: rgba(0, 128, 128, 1)"> 6</span> select(): <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">实现接口同时实现继承接口继承的类</span>
<span style="color: rgba(0, 128, 128, 1)"> 9</span> <span style="color: rgba(0, 0, 0, 1)">class Button extends Control implements SelectableControl {
</span><span style="color: rgba(0, 128, 128, 1)">10</span> <span style="color: rgba(0, 0, 0, 1)">select() { }
</span><span style="color: rgba(0, 128, 128, 1)">11</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">12</span>
<span style="color: rgba(0, 128, 128, 1)">13</span> <span style="color: rgba(0, 0, 0, 1)">class TextBox extends Control {
</span><span style="color: rgba(0, 128, 128, 1)">14</span> <span style="color: rgba(0, 0, 0, 1)">select() { }
</span><span style="color: rgba(0, 128, 128, 1)">15</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">16</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">实现接口同时实现继承接口继承的类的子类</span>
<span style="color: rgba(0, 128, 128, 1)">17</span> <span style="color: rgba(0, 0, 0, 1)">class TextBox1 extends TextBox implements SelectableControl{
</span><span style="color: rgba(0, 128, 128, 1)">18</span>
<span style="color: rgba(0, 128, 128, 1)">19</span> }</pre>
</div>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
</div>
<div id="MySignature" role="contentinfo">
——生命自会找到蓬勃之路。<br><br>
来源:https://www.cnblogs.com/ZheOneAndOnly/p/11780550.html
頁:
[1]