TS — interface 接口
最后更新于:2022-04-02 08:11:15
[TOC]
>[success] # TS -- 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,在这基础上通过语言的对比,和描述希望可以对前端
本身没有接口概念的开发一点帮助
~~~
>[info] ## 开始TS的接口
~~~
1.可选类型 -- 用'?'号修饰
2.索引签名 -- 可以添加不确定参数
3.限制接口中的参数是只读 -- readonly
4.接口 数组 和只读
5.接口定义函数
6.接口做闭包(混合类型)
7.绕过接口的多余参数检查-- 三种方式
~~~
>[danger] ##### 通过几个例子了解ts 接口
~~~
1.例子来自'官方文档',改进了解接口
2.下面的第一个案例是按照官网思路进行改进的为了更加直观,有一个 方法
用了打印个人信息的,我们用'ts' 约束了 传递参数,有几个分别是什么类型
3.看完下面的案例其实深入思考,可以指定传入的对象每一个key规定类
型,和传递参数,缺点灵活性不高,不能将公共格式参数的提取出来复用
~~~
* 根据官网案例的思路改进
~~~
// 这里用了ts规定了parmasinfo 参数格式
function printPesonInfo(parmasinfo:{name:string,sex:string}) {
console.log(`姓名:${parmasinfo.name }性别:${parmasinfo.sex}`)
}
// 错误使用因为没有使用定义的sex
// let paramsinfo = {name:'wang',age:12}
let paramsinfo = {name:'wang',age:12,sex:'男'}
printPesonInfo(paramsinfo) // 姓名:wang性别:男
~~~
>[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
}
// 人
function printPesonInfo(parmasinfo: Baseinfo) {
console.log(`姓名:${parmasinfo.name }`)
}
// 接口中的索引签名other 就会收到age
printPesonInfo( {name:'wang',age:13}) // wang
~~~
* 案例二的错误示范
~~~
// 错误示范
interface Person {
name: string;
age?: number; // 必须是string类型才行,需要是propName类型的子集
[propName: string]: string; // 改正 [propName: string]: any;
}
}
~~~
* 案例三
~~~
interface Person {
name: string;
age?: number; // 必须是string类型才行,需要是propName类型的子集
[propName: string]: any;
}
let tom: Person = {
name: 'Tom',
age: 25,
1: 'male' // 因为key 会调用 自带的toString 方法
};
~~~
>[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 = 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] ##### 绕过接口的多余参数检查-- 三种方式
* 什么是接口的多余参数检查
~~~
interface Baseinfo {
name:string,
sex?:string
}
// 人
function printPesonInfo(parmasinfo: Baseinfo) {
console.log(`姓名:${parmasinfo.name }`)
}
// 如果直接传递参数,且传递的参数key未在接口中定义会提示错误
printPesonInfo( {name:'wang',age:13} ) // 报错的
~~~
* 第一种解决使用类型断言
~~~
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
~~~
';