Interface(接口分享)第一节
一、接口初探
- 有时候我们传入的参数可能会包含很多的属性,但是编译器只会检查那些必须的属性是否存在,以及类型是否匹配,而咱们要讲的接口其实就是用来描述下面这个例子里的结构,对于接口传入的数据咱们只关心它的外形,只关心他传入的对象是够满足咱们接口的限定条件,满足咱们就认定他是正确的
function Animal(config: {name: string, age: number}) {
console.log("我叫:" + config.name + "今年" + config.age + "岁了")
}
console.log(Animal({ name: "yxl", age: 24 }))
// 下面重构
interface Config {
name: string
age: number
}
function Animal(config: Config) {
console.log("我叫:" + config.name + "今年" + config.age + "岁了")
}
/*
* 这里把接口限制的类型付给了变量myAnimal,即使咱们传入了接口中没有限制的属性,
* 这里编译之后也不会出现报错,是因为接口类型检查不会对变量赋值进行检查
* 如果咱们这里把Animal({name: "yxl", age: 24, color: "黑色的头发"})这样传参的话,
* 接口类型检查会报出当前color属性没有在Config接口中进行限制,所以是不被允许的
*/
let myAnimal = { name: "yxl", age: 24, color: "黑色的头发" }
console.log(Animal(myAnimal))
二、可选属性
- 接口里的属性有时候不是必须的,有的咱们可以用到,有的 用不到,这个时候可选属性接口就是一个不错的选择,可选属性的好处就是咱们可以对可能存在的属性进行预先定义,其次是能够捕获不存在属性是的一个错误
interface Config {
name: string
age?: number
// [propName: string]: any 字符串索引签名
}
function Animal(config: Config) {
console.log("我叫:" + config.name + "今年" + config.age + "岁了")
}
/*
* 这里将Animal传参中的age咱们故意打错了个字母,这个时候你就会发现当前接口会对这个属性进行检查
* 接口会对当前ages报错,不存在于当前接口规范中,这个时候为了避免这种报错可以采用类型断言,告诉这个接口,
* 当前穿的参数就是你的规范,这个时候可以发现错误消失了,还有另一种方法是通过索引签名的方式进行屏蔽错误
* [propName: string]: any 这个索引签名就是为了你能够预见某个对象可能觉有某些特殊的用途而准备的。
*/
console.log(Animal({ name: "yxl", ages: 24 } as Config))
三、只读属性
- 一些对象属性只能在对象刚刚创建的时候修改其值。 你可以在属性名前用 readonly 来指定只读属性:
interface Point {
readonly x: number
readonly y: number
}
let p:Point = { x: 12, y: 14 }
p.x = 15 // 错误
/*
* TypeScript 具有 ReadonlyArray<T> 类型,它与 Array<T> 相似,只是把所有可变方法去掉了,
* 因此可以确保数组创建后再也不能被修改:
*/
let a: number[] = [1, 2, 3]
let aa: ReadonlyArray<number> = a
aa[0] = 14; // Index signature in type 'readonly number[]' only permits reading.
aa.push(4) // Property 'push' does not exist on type 'readonly number[]'.
aa.length = 10 // Cannot assign to 'length' because it is a read-only property.
a = aa as number[] // 类型断言为数字组成的数组
a[0] = 15
四、函数类型
- 接口能够描述JavaScript中对象拥有的各种各样的外形。除了描述带有属性的普通对象外,接口也可以描述函数类型。接下来我们一起看一下函数类型接口是怎么使用的
interface SearchFun {
(source: string, subString: string): Boolean
}
let mySearch: SearchFun // @1
/*
* 这里对声明了一个匿名函数,并且将这个匿名函数付给了变量mySearch,并且同时
* 给这个匿名函数进行了传参,当然这个传参遵循了SearchFun接口规范,
* 接口会自动推断参数的类型,因为咱们已经将mySearch函数付给了SearchFun类型变量
* 注意: 函数类接口不同于属性类接口,要求属性的变量相同,这里变量可以不同,只需要保证变量的类型为string就行
* function(a, b): Boolean
* mySearch = function (a, b): Boolean { 这个方案也可,因为@1中已经将函数付给了接口类型变量
* */
mySearch = function (source: string, subString: string): Boolean {
let result = source.search(subString);
return result > -1
}
console.log(mySearch("http://b28.sy.souyoung.com/ad/cpcAuction", "28")) // true
五、可索引类型
- TypeScript 支持两种索引签名:字符串和数字。 可以同时使用两种类型的索引,但是数字索引的返回值必须是字符串索引返回值类型的子类型。 这是因为当使用 number 来索引时,JavaScript 会将它转换成string 然后再去索引对象。 也就是说用 100(一个 number)去索引等同于使用'100'(一个 string )去索引,因此两者需要保持一致。接下来看看如何使用:
/*
* 第一种情况数字类型索引NumberArr的时候返回值是string 这个时候调用a[0] 得到了Bob
* [index: number]: string
* 第二种情况是字符串索引NumberArr的时候返回值是string or number,这个时候
* 返回值是string调用:a["name"] 得到了Bob 返回值是number调用:a["name"] 得到
* 了数字:1
* [index: string]: string
* let a: NumberArr = {
* "name": "Bob"
* }
* * [index: string]: number
* let a: NumberArr = {
* "age": 24
* }
* */
interface NumberArr {
[index: number]: string
}
let a: NumberArr = ["Bob", "Jerry"] // 可
// let a: NumberArr = [55, 66] 不可
console.log(a[0]) // 可
class Animal {
name: string
}
class Dog extends Animal {
breed: string
}
interface NotOkay {
[x: string]: Animal // Numeric index type 'Animal' is not assignable to string index type 'Dog'.
[y: number]: Dog
}
/*
* 上边的例子很好的诠释了两种索引类型可以同时使用,但是这两者又必须
* 遵循之间的规则,那就是数字索引的返回值必须是字符串索引返回值类型的子类型
* 上边Animal并不是Dog的子类型,刚好弄反了,所以咱们在运行编译的时候会
* 报错。下面是正确的使用方式
* interface NotOkay {
* [x: string]: Animal
* [y: number]: Dog
* }
* 下面的例子是对类进行了约束
* */
interface Animal {
// 定义类的name属性值
name: string;
// 定义类中的方法
eat(name: string, gender: string): void
}
class Dog implements Animal {
name: string;
constructor(name: string){
this.name = name;
};
// 注意接口定义的方法有参数,当你不传也不会报错
eat() {
console.log("defind success")
}
}
var dog = new Dog("pika")
dog.eat()
class Cat implements Animal {
name: string;
constructor(name: string){
this.name = name;
};
eat(name: string, gender: string) {
console.log(`${this.name} is ${gender} cat like eat ${name}`)
}
}
var cat = new Cat("herry")
cat.eat("fish", "male")
/*
* 接口描述了类的公共部分,而不是私有跟公共两部分,他不会帮你检查类是够具有某些私有成员。
* 当一个类去实现一个接口的时候,他只会对其实例部分进行检查。constructor存在于类的静态部分,所以不再检查范围内。
*/
六、接口继承
- 和类一样,接口也可以相互继承。 这让我们能够从一个接口里复制成员到另一个接口里,可以更灵活地将接口分割到可重用的模块里。下面是实际应用的例子一起看一下:
interface Animal {
name: string
say(): void
}
interface Person extends Animal {
work(): void
closer: string
}
class Progremmer implements Person {
closer: string;
name: string;
say(): void {
console.log(`${this.name}说我喜欢穿${this.closer}`)
}
work(): void {
console.log(`${this.name}说工作使我快乐!!!`)
}
constructor(name: string, closer: string) {
this.name = name;
this.closer = closer;
}
}
let g:Person = new Progremmer("小明", "花衣服")
g.say();
g.work();
/*
* 上边中的接口继承了接口,就意味着person这个接口有了Animal的属性以及方法
* 这个时候咱们定义的程序员类去实现这个Person,实现这个person接口就意味着类必须实现
* 这个接口中的方法跟属性,上述例子有体现
*/
七、混合类型
- 接口能够描述 JavaScript 里丰富的类型。 因为 JavaScript 其动态灵活的特点,有时你会希望一个对象可以同时具有上面提到的多种类型。
interface Counter {
(start: number): string
name: string
say(str: string): void
}
/*
* 声明一个接口,如果只有(start: number): string一个成员,那么这个接口就是函数接口,
* 同时还具有其他两个成员,可以用来描述对象的属性和方法,这样就构成了一个混合接口。
*/
function myCounter(): Counter {
function counter(start: number): string {
return ""
}
/*
* function counter实现了接口的描述,成为了一个函数,因为myCounter是Counter类型* 的,所以counter还具有name属性跟say方法
*/
counter.name = "yxl"
counter.say = function (str: string) {
console.log(`我要学习${str}`)
}
let myCounters: Counter = counter
return myCounters
}
let s = myCounter();
s(10);
s.name= "sss";
s.say("TypeScript");
/*
* 官方文档这里使用了类型断言
* function counter(): Counter {
* let myCounters = (function (start: number) { }) as Counter
* myCounters.name = "yxl"
* myCounters.say = function (str: string) {
* console.log(`我要学习${str}`)
* }
* return myCounters
* }
*/
Interface(接口分享)第一节的更多相关文章
- 第一节 如何用Go实现单链表
一.概念介绍 下面这副图是我们单链表运煤车队. 每节运煤车就是单链表里的元素,每节车厢里的煤炭就是元素中保存的数据.前后车通过锁链相连,作为单链表运煤车,从1号车厢开始,每节车厢都知道后面拉着哪一节车 ...
- Ext JS学习第十六天 事件机制event(一) DotNet进阶系列(持续更新) 第一节:.Net版基于WebSocket的聊天室样例 第十五节:深入理解async和await的作用及各种适用场景和用法 第十五节:深入理解async和await的作用及各种适用场景和用法 前端自动化准备和详细配置(NVM、NPM/CNPM、NodeJs、NRM、WebPack、Gulp/Grunt、G
code&monkey Ext JS学习第十六天 事件机制event(一) 此文用来记录学习笔记: 休息了好几天,从今天开始继续保持更新,鞭策自己学习 今天我们来说一说什么是事件,对于事件 ...
- 第一节:《线程安全和锁Synchronized概念》
第一节:线程安全和锁Synchronized概念 一.进程与线程的概念 (1)在传统的操作系统中,程序并不能独立运行,作为资源分配和独立运行的基本单位都是进程. 在未配置 OS 的系统中,程序的执行方 ...
- 我的第一节Android课
我的第一节安卓课程,今天非比寻常的一天,我开始了我程序猿之路的第一节安卓课程,安卓课程只是我的一个兴趣班,我的本专业是java开发,因为喜欢做一个属于自己的一个手机APP,就选多个一样技能,毕竟十八般 ...
- 第四章 跨平台图像显示库——SDL 第一节 与SDL第一次亲密接触
http://blog.csdn.net/visioncat/article/details/1596576 GCC for Win32 开发环境介绍(5) 第四章 跨平台图像显示库——SDL 第一节 ...
- seajs第一节,seajs基本使用
什么是seajs,它是干什么使用的,可以去网上搜索一下, 官网:http://seajs.org/docs/ 基本使用seajs <!DOCTYPE html> <html> ...
- VUE2.0实现购物车和地址选配功能学习第一节(来源--慕课网河畔一角)
第一节 vue知识 vue-resource:和后台交互的一个插件,实现get.post和jsonp等功能.(替代jQuery) vue特点: 1.易用:通过创建vue实例,{{}}绑定数据十分方便 ...
- go interface接口
一:接口概要 接口是一种重要的类型,他是一组确定的方法集合. 一个接口变量可以存储任何实现了接口方法的具体值.一个重要的例子就是io.Reader和io.Writer type Reader inte ...
- 第一节:.Net版基于WebSocket的聊天室样例
一. 说在前面的话 该篇文章为实时通讯系列的第一节,基于WebSocket编写了一个简易版聊天样例,主要作用是为引出后面SignalR系列的用法及其强大方便之处,通过这个样例与后续的SignalR对比 ...
- 第一节:ASP.NET开发环境配置
第一节:ASP.NET开发环境配置 什么是ASP.NET,学这个可以做什么,学习这些有什么内容? ASP.NET是微软公司推出的WEB开发技术. 2002年,推出第一个版本,先后推出ASP.NET2. ...
随机推荐
- devops-持续集成管理之SonarQube
1. devops-持续集成管理之SonarQube 1) 代码质量七宗罪 编码规范:是否遵守了编码规范,遵循了最佳实践. 潜在的BUG:可能在最坏情况下出现问题的代码,以及存在安全漏洞的代码. 文 ...
- 多测师讲解_007 hashlib练习
#Hash,译做"散列",也有直接音译为"哈希"的.把任意长度的输入,通过某种hash算法,变换成固定长度的输出,该输出就是散列值,也称摘要值.该算法就是哈希函 ...
- day24 Pyhton学习 反射
一.isinstance,type,issubclass issubclass() 这个内置函数可以帮我们判断x类是否是y类的子类 issubclass(x,y) class Base: pass c ...
- DFS深度优先搜索算法
Lake Counting(POJ No.2386) 有一个大小为N*M的园子,雨后积起了水.八连通的积水被认为是在一起的.请求出园子里共有多少个水洼?(八连通是指下图中相对w的*部分) * * * ...
- git tag的应用
一,git的tag是什么? tag就是给commit起一个容易记忆容易理解的名字 说明:架构森林是一个专注架构的博客,地址:https://www.cnblogs.com/architectfores ...
- 在 Istio 中实现 Redis 集群的数据分片、读写分离和流量镜像
Redis 是一个高性能的 key-value 存储系统,被广泛用于微服务架构中.如果我们想要使用 Redis 集群模式提供的高级特性,则需要对客户端代码进行改动,这带来了应用升级和维护的一些困难.利 ...
- codeforces#426(div1) B - The Bakery (线段树 + dp)
B. The Bakery Some time ago Slastyona the Sweetmaid decided to open her own bakery! She bought req ...
- win10使用U盘安装Linux系统教程
win10安装Linux系统详细教程 目前想要再Windows系统上安装Linux系统有三种方式:其一是安装在虚拟机上(VMWare或者VirtualBox),其二是使用win10最新支持的Linux ...
- vue项目中mockjs的使用
mock.js是一个库,源码托管:https://github.com/nuysoft/Mock github上的原话:Mock.js是一个模拟数据生成器,可帮助前端开发和原型与后端进度分开,并减少某 ...
- 关于spring @scope("prorotype") 和 @aspectj 一起用的问题
前段时间听别人说prototype 模式的bean用@Aspectj做AOP会导致内存泄漏, 于是自己研究了下总结出几点 1.aspectj 如果是采用javac 编译 会动态产生代理类 代理类是 ...