ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
[TOC] >[success] # 其他语言 interface 接口 [第一条的参考文章](https://blog.csdn.net/qq_21033779/article/details/79071887) ~~~ 1.了解什么是接口:接口只是定义了一些方法,而没有去实现,多用于程序 设计时,只是设计需要有什么样的功能,但是并没有实现任何功能,这些功 能需要被另一个类(B)继承后,由 类B去实现其中的某个功能或全部功能 '接口定义了多个类的公共行为规范,这些行为是和外部进行交流的通道' 2.疯狂java 讲义中描述接口(这里笔者稍微改动了下):电脑主板上有usb接 口,但是不同时期usb接口遵循不同的协议,必须遵循了这个协议才能享受 对应不同时期usb 版本带来的体验,这个规范我们可以理解成接口,他定义 了一些规则,但具体的方法我们实现这个接口的时候各大厂商按照自己优化 去实现,好处是让规范和实现分离,让软件之间面向接口耦合,是一种松耦 合的设计,这样主板就不会关心这个是那个厂家制造的usb,也不管你的内 部实现,只要你遵循了我的协议,我们就能匹配。'java' 还利用接口的特性 实现了多继承 3.pyhon 角度来看,pyhon没有明确接口概念,使用的抽象类来变相实现, 加上本身的多继承的特性,也让他可以将接口这个概念和其他语言划分开 4.上面是通过csdn作者--' leeyan85'和疯狂java讲义书中加上笔者本身略微 学习过pyhon 和 java,在这基础上通过语言的对比,和描述希望可以对前端 本身没有接口概念的开发一点帮助 ~~~ >[success] # TS -- 接口 通过案例来看ts 中的接口 ~~~ function printPersonInfo(paramsInfo: { name: string; sex: string }) { console.log(`姓名:${paramsInfo.name}性别:${paramsInfo.sex}`) } let paramsInfo = { name: 'wang', age: 12, sex: '男' } printPersonInfo(paramsInfo) // 姓名:wang性别:男 // 错误使用因为没有使用定义的sex // let paramsInfo = {name:'wang',age:12} // printPersonInfo(paramsInfo) // 报错 错误使用因为没有使用定义的sex ~~~ ~~~ 1.虽然实现了,和传递参数,缺点灵活性不高,如果在遇到相同类似的结构,不能将公共格式参数的提取出来复用,这种情况下 就可以使用'接口' ~~~ >[info] ## 接口定义 ~~~ 1.TypeScript 对对象的类型检测遵循一种被称之为“鸭子类型”(duck typing)或者“结构化类型(structural subtyping)”的准则, 即只要两个对象的结构一致,属性和方法的类型一致,则它们的类型就是一致的。 2.接口的作用就是为这些类型命名和为你的代码或第三方代码定义契约 ~~~ >[danger] ##### 了解接口 -- interface ~~~ 1. 使用在变量前声明'interface' 2. 简单案例: 声明一个interface: interface person { name: string; age: number; } 然后就可以使用这个interface来限制一个对象的类型: let tom: person = { name: 'tom', age: 12 } 3.和刚才比我们解决了缺点中的问题可以公共提取,规范一个系列 ~~~ * 所有动物都有一个最基本的信息名字和性别,必须按照这个规范来创建 ~~~ interface Baseinfo { name:string, sex:string } // 人 function printPesonInfo(parmasinfo: Baseinfo) { console.log(`姓名:${parmasinfo.name }性别:${parmasinfo.sex}`) } // 动物 function printAnimalInfo(parmasinfo: Baseinfo) { console.log(`姓名:${parmasinfo.name }性别:${parmasinfo.sex}`) } let paramsinfo = {name:'wang',age:12,sex:'男'} printPesonInfo(paramsinfo) // 姓名:wang性别:男 let paramsAnimainfo = {name:'小黑',age:12,sex:'公'} printAnimalInfo(paramsAnimainfo) // 姓名:小黑性别:公 ~~~ >[danger] ##### 可选类型 -- 用'?'号修饰 ~~~ 1.现在我们发现不是接口中提供的每一个参数我们都需要,为此'TS' 提供了 一种'?' 来修饰,被问号修饰的参数就是可以选传,不是必须参数 ~~~ ~~~ interface Baseinfo { name:string, sex?:string } // 人 function printPesonInfo(parmasinfo: Baseinfo) { console.log(`姓名:${parmasinfo.name }`) } let paramsinfo = {name:'wang'} printPesonInfo(paramsinfo) // 姓名:wang ~~~ >[danger] ##### 索引签名 -- 可以添加不确定参数 ~~~ 1.刚才的问号让我们可以选填一些参数,但是如果需要增加一些不确定 参数就需要使用 '索引签名' 2.利用这个可以规定你的索引签名的类型(即使你的索引规定是string类型 但也可以使用数字,案例二有说明) 3.主要注意这里有个问题:需要注意的是,一旦定义了任意属性, 那么'确定属性和可选属性的类型都必须是它的类型的子集'(案例三) ~~~ * 案例一 ~~~ interface Baseinfo { name:string, sex?:string, [other:string]:any //可以叫任意名字这里叫other 你也可叫aaaa } // 人 function printPesonInfo(parmasinfo: Baseinfo) { console.log(`姓名:${parmasinfo.name }`) } // 接口中的索引签名other 就会收到age printPesonInfo( {name:'wang',age:13}) // wang ~~~ * 案例二的错误示范 ~~~ interface Person { name: string; age?: number; [propName: string]: any; } let tom: Person = { name: 'Tom', age: 25, 1: 'male' // 因为key 会调用 自带的toString 方法 }; ~~~ * 案例三 ~~~ // 错误示范 // age 和name 必须是 任意属性的子集 interface Person { name: string age?: number // 报错 [propName: string]: string // 改正 [propName: string]: any; 或者 [propName: string]: string|number } ~~~ * 最优方法 https://www.kancloud.cn/book/cyyspring/tyscript/preview/ts--%E7%B1%BB%E5%9E%8B%E7%BC%A9%E5%87%8F.md >[danger] ##### 限制接口中的参数是只读 -- readonly ~~~ 1.readonly 和 const 都是只读,但两者如何用区别在哪里,首先'readonly ' 是'TS' 在接口提出,只针对接口中的参数赋值后就禁止更改,而const 是 es6 提出的针对变量,不让变量进行更改 2.用'ts' 文档的总结来说:最简单判断该用readonly还是const的方法是看要 把它做为变量使用还是做为一个属性。 做为变量使用的话用const,若做 为属性则使用readonly。 ~~~ * 使用 ~~~ interface Point { readonly x: number; readonly y: number; } // p1 是接口Point 类型 let p1: Point = { x: 10, y: 20 }; p1.x = 5; // error! 已经设置了readonly 属性所以禁止更改 ~~~ >[danger] ##### 接口 数组 和只读 ~~~ 1.我们还可以利用接口定义数组位置的类型,和元组不同,元组不仅限制 了类型也限制了最开始赋值时候的长度(push 还是可以往元组添加东西的) ~~~ * 接口定义数组 ~~~ // 接口 数组 和只读 // 定义了一个数组接口,数组第一位必须数字,第二位是字符串 interface ArrInter { 0:number, 1:string } let arr: ArrInter = [1,"w",3] console.log(arr) ~~~ * 接口 数组 和只读 ~~~ // 定义了一个数组接口,数组第一位必须数字,第二位是字符串 interface ArrInter { readonly 0:number, 1:string } let arr: ArrInter = [1,"w",3] arr[0] = 5 // erro 后续禁止改变 ~~~ >[danger] ##### 接口定义函数 ~~~ 1.接口不止能定义变量值也可以定义函数 ~~~ * 将BaseInfo 加工 ~~~ // 定义了一个信息接口,里面有姓名,年龄和一个吃的方法返回的类型是string类型 interface BaseInfo{ name:string, age:number, eat(food: string):string } const personInfo:BaseInfo = { name:'wang', age:99, eat(parmas){ return parmas } } ~~~ * 只定义 方法的接口 ~~~ 1.对于函数类型的类型检查来说,函数的参数名不需要与接口里定义的名字相匹配 2.函数的参数会逐个进行检查,要求对应位置上的参数类型是兼容的 ~~~ ~~~ interface SearchFunc { (source: string, subString: string): boolean; } let mySearch: SearchFunc; mySearch = function(src: string, sub: string): boolean { let result = src.search(sub); return result > -1; } ~~~ * 类型别名 ~~~ // ts箭头函数不加大括号的含义是 返回 类型 type PersonInfo = (name:string) => string // 这里箭头函数是正常的js 表达的意思 let personName:PersonInfo = (name) => name // 做一个小备注冒号后面等号前面属于ts定义, (x: number, y: number, z?:number) => number // 是ts的定义这里=> 不是js箭头函数 const add2: (x: number, y: number, z?:number) => number = add ~~~ >[danger] ##### 接口做闭包(混合类型) ~~~ 1.利用function 也可以定义key的方式 ~~~ * 有时候,一个函数还可以有自己的属性和方法: ~~~ 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; ~~~ * 编译后效果 ~~~ function getCounter() { var counter = function (start) { }; counter.interval = 123; counter.reset = function () { }; return counter; } var c = getCounter(); c(10); c.reset(); c.interval = 5.0; ~~~ * 案例二 编译前 ~~~ interface Counter { (): void; count: number; } function getCounter(): Counter { const c = ()=>{ c.count++ } c.count = 0 return c } ~~~ * 编译后 ~~~ function getCounter() { var c = function () { c.count++; }; c.count = 0; return c; } ~~~ >[danger] ##### 继承接口 ~~~ 1.接口类型可以继承和被继承,比如我们可以使用如下所示的 extends 关键字实现接口的继承。 ~~~ ~~~ interface DynamicLanguage { rank: number // 定义新属性 } interface TypeSafeLanguage { typeChecker: string // 定义新的属性 } /** 继承多个 */ interface TypeScriptLanguage extends DynamicLanguage, TypeSafeLanguage { name: 'TypeScript' } ~~~ * 我们仅能使用兼容的类型覆盖继承的属性 ~~~ { interface DynamicLanguage { rank: number // 定义新属性 } interface TypeSafeLanguage { typeChecker: string // 定义新的属性 } /** 继承多个 */ interface TypeScriptLanguage extends DynamicLanguage, TypeSafeLanguage { name: 'TypeScript' } /** ts(6196) 错误的继承,name 属性不兼容 */ interface WrongTypeLanguage extends TypeScriptLanguage { typeChecker: number; // typeChecker: string; 可以的 } } ~~~