终于来到了比较重要的知识,接口,有多重要呢,反正是很重要好啵

在 TypeScript 中,我们使用接口(Interfaces)来定义对象的类型。

那什么是接口呢,在面向对象语言中,接口(Interfaces)是一个很重要的概念,它是对行为的抽象,而具体如何行动需要由类(classes)去实现(implements)

TypeScript 中的接口是一个非常灵活的概念,除了可用于对类的一部分行为进行抽象以外,也常用于对「对象的形状(Shape)」进行描述。

少侠:这是个什么东西,看不太懂啊

机智的我:少侠,少侠我懂,你家里有锁吗(别说没有啊,没有这天就聊死了)。

少侠:有,咋的了?

机智的我:我准备用锁来给你解释一下什么是接口,锁就是接口

少侠:瞎扯,看刀!

机智的我:(躲躲躲)少侠这是真的啊,接口就像你家的锁,钥匙就像是一个个的类,要想和锁匹配打开锁,就只能根据锁里面的锁芯来实现钥匙的样子

少侠:有点意思啊

机智的我:我说的有点道理吧少侠,来让我们继续看看代码怎么实现的

//定义一个接口
interface Person {
name: string;
age: number;
} let tom: Person = {
name: 'Tom',
age:
};

简单吧,下面让我们再看看另外两个例子

第一个例子:

interface Person {
name: string;
age: number;
} let tom: Person = {
name: 'Tom'
}; // index.ts(6,5): error TS2322: Type '{ name: string; }' is not assignable to type 'Person'.
// Property 'age' is missing in type '{ name: string; }'.

为啥报错了呢,因为定义的变量比接口少了一些属性是不允许的,你想要是允许,那不乱了套了吗,少了一截的钥匙都能打开锁,那我要这锁有何用?

第二个例子

interface Person {
name: string;
age: number;
} let tom: Person = {
name: 'Tom',
age: ,
gender: 'male'
}; // index.ts(9,5): error TS2322: Type '{ name: string; age: number; gender: string; }' is not assignable to type 'Person'.
// Object literal may only specify known properties, and 'gender' does not exist in type 'Person'.

哎哟,少了不行,多了也不行吗?对的,定义的变量比接口多了一些属性也是不允许的,

可见,赋值的时候,变量的形状必须和接口的形状保持一致。就跟钥匙必须和锁芯完全匹配才可以一样一样的

少侠:这木简单,我学会了

机智的我:别急啊少侠,下面还有呢

进行下面的学习时请忘掉上面锁的例子,锁的例子只匹配最基础的接口的用法,放在下面就不合适了

有时我们希望不要完全匹配一个形状,那么可以用可选属性(?)

interface Person {
name: string;
age?: number;
} let tom: Person = {
name: 'Tom'
};
interface Person {
name: string;
age?: number;
} let tom: Person = {
name: 'Tom',
age:
};

你看,上面两种都不报错,说明我们的可选属性生效了,可选属性的含义是该属性可以不存在。

这时仍然不允许添加未定义的属性:

interface Person {
name: string;
age?: number;
} let tom: Person = {
name: 'Tom',
age: ,
gender: 'male'
}; // examples/playground/index.ts(9,5): error TS2322: Type '{ name: string; age: number; gender: string; }' is not assignable to type 'Person'.
// Object literal may only specify known properties, and 'gender' does not exist in type 'Person'.

你看,又报错了,来我们看下解决方法

任意属性:

有时候我们希望一个接口允许有任意的属性,可以使用如下方式:

interface Person {
name: string;
age?: number;
[propName: string]: any;
} let tom: Person = {
name: 'Tom',
gender: 'male'
};

使用 [propName: string] 定义了任意属性取 string 类型的值

需要注意的是,一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集(特别注意)

interface Person {
name: string;
age?: number;
[propName: string]: string;
} let tom: Person = {
name: 'Tom',
age: ,
gender: 'male'
}; // index.ts(3,5): error TS2411: Property 'age' of type 'number' is not assignable to string index type 'string'.
// index.ts(7,5): error TS2322: Type '{ [x: string]: string | number; name: string; age: number; gender: string; }' is not assignable to type 'Person'.
// Index signatures are incompatible.
// Type 'string | number' is not assignable to type 'string'.
// Type 'number' is not assignable to type 'string'.

上例中,任意属性的值允许是 string,但是可选属性 age 的值却是 numbernumber 不是 string 的子属性,所以报错了。

就是说你一旦将任意属性设置为string,那木接口里面所有属性的取值必须为string

另外,在报错信息中可以看出,此时 { name: 'Tom', age: 25, gender: 'male' } 的类型被推断成了 { [x: string]: string | number; name: string; age: number; gender: string; },这是联合类型和接口的结合。

只读属性:

有时候我们希望对象中的一些字段只能在创建的时候被赋值,那么可以用 readonly 定义只读属性

interface Person {
readonly id: number;
name: string;
age?: number;
[propName: string]: any;
} let tom: Person = {
id: ,
name: 'Tom',
gender: 'male'
}; tom.id = ; // index.ts(14,5): error TS2540: Cannot assign to 'id' because it is a constant or a read-only property.

上例中,使用 readonly 定义的属性 id 初始化后,又被赋值了,所以报错了。

注意,只读的约束存在于第一次给对象赋值的时候,而不是第一次给只读属性赋值的时候:

interface Person {
readonly id: number;
name: string;
age?: number;
[propName: string]: any;
} let tom: Person = {
name: 'Tom',
gender: 'male'
}; tom.id = ; // index.ts(8,5): error TS2322: Type '{ name: string; gender: string; }' is not assignable to type 'Person'.
// Property 'id' is missing in type '{ name: string; gender: string; }'.
// index.ts(13,5): error TS2540: Cannot assign to 'id' because it is a constant or a read-only property.

上例中,报错信息有两处,第一处是在对 tom 进行赋值的时候,没有给 id 赋值。

第二处是在给 tom.id 赋值的时候,由于它是只读属性,所以报错了。

参考资料:https://github.com/xcatliu/typescript-tutorial/blob/master/basics/type-of-object-interfaces.md

TS学习随笔(三)->接口的更多相关文章

  1. TS学习随笔(七)->声明文件

    now我们来看一看TS怎么声明文件, 在JS里面我们经常会使用各种第三方类库,引入方式也不太相同,常见的就是在HTML中通过script标签引入,然后就可以使用全局变量$或者jQuery了 我们通常这 ...

  2. TS学习随笔(四)->数组的类型

    少侠们,今天我们继续来搞一搞TS 今天我们要来看一看TS中数组的定义是个什么鬼样子 数组的类型: 在 TypeScript 中,数组类型有多种定义方式,比较灵活.下面我们来看看有哪些定义方法 「类型 ...

  3. TS学习随笔(五)->函数

    这篇文章我们来看一下TS里面的函数 函数声明 在 JavaScript 中,有两种常见的定义函数的方式——函数声明(Function Declaration)和函数表达式(Function Expre ...

  4. TS学习随笔(一)->安装和基本数据类型

    去年学过一段时间的TS,但由于在工作中不常用.就生疏了,最近项目要求用TS,那我就再回去搞搞TS,写一篇记录一下自己学习TS的进度以及TS知识点 首先,关于TS的定义我就不在这描述了,想看百度一下你就 ...

  5. android 项目学习随笔三(Fragment )

    1.在主页面(activity引用Fragment )的布局文件中定义FrameLayout ,加载Fragment  <FrameLayout xmlns:android="http ...

  6. TS学习随笔(六)->断言

    now,我们来看一看TS里面的断言,听起来很上档次啊,其实看完你就发出惊叹,这就是断言啊 类型断言 类型断言(Type Assertion)可以用来手动指定一个值的类型 语法 <类型>值 ...

  7. TS学习随笔(二)->类型推论,联合类型

    这篇内容指南:        -----类型推论  -----联合类型 类型推论 第一篇中我们看了TS的基本使用和基本数据类型的使用,知道了变量在使用的时候都得加一个类型,那我们可不可以不加呢,这个嘛 ...

  8. JavaSE 第二次学习随笔(三)

    * 常见异常 * 数组越界异常 * 空指针异常 * * * 特点: 当程序出现异常的时候, 程序会打印异常信息并中断程序 * 所以当同时出现多个异常的时候只能执行第一个, 后边的用不到 * * 单异常 ...

  9. android 学习随笔三(测试与单元测试框架)

    测试 1.按岗位: 黑盒测试:测试业务逻辑 白盒测试:测试逻辑方法 2.按测试粒度 方法测试 function 单元测试 unit 集成测试 integration 系统测试 system 3.按暴力 ...

随机推荐

  1. webapi 知识点

    在web api 中后台的方法必须 加入 [HttpGet] ,[HttpPost],[HttpPut],[HttpDelete] 来区分,这是一种习惯. ps: get 方式参数都存在http协议头 ...

  2. JNI实战(一):JNI HelloWorld

    使用最新Android Studio的Cmake,创建一个Native C++项目后,我们就可以看到JNI的Hello World的项目及示例代码了. JNI的项目代码,分为三层:Java层,C++层 ...

  3. [Swift]LeetCode640. 求解方程 | Solve the Equation

    Solve a given equation and return the value of x in the form of string "x=#value". The equ ...

  4. 快速搭建WebAPI(Odata+Code-First)附Odata条件查询表~

    Odata是什么? 开放数据协议(Open Data Protocol,缩写OData)是一种描述如何创建和访问Restful服务的OASIS标准.该标准由微软发起,前三个版本1.0.2.0.3.0都 ...

  5. Object Pooling(对象池)实现

    在文章开始之前首先要思考的问题是为什么要建立对象池.这和.NET垃圾回收机制有关,正如下面引用所说,内存不是无限的,垃圾回收器最终要回收对象,释放内存.尽管.NET为垃圾回收已经进行了大量优化,例如将 ...

  6. Chapter 4 Invitations——18

    But they were all in, and Edward was speeding away. 但是他们都在里面了之后,Edward就加速走了. I drove home slowly, ca ...

  7. [软件开发技巧]·树莓派极简安装OpenCv

    树莓派极简安装OpenCv 个人主页–> https://xiaosongshine.github.io/ 因为最近在开发使用树莓派+usb摄像头识别模块,打算用OpenCv,发现网上的树莓派O ...

  8. WebGL 纹理颜色原理

    本文由云+社区发表 作者:ivweb qcyhust 导语 WebGL绘制图像时,往着色器中传入颜色信息就可以给图形绘制出相应的颜色,现在已经知道顶点着色器和片段着色器一起决定着向颜色缓冲区写入颜色信 ...

  9. 1.Docker简介【Docker每天5分钟】

    Docker给PaaS世界带来的“降维打击”,其实是提供了一种非常便利的打包机制.该机制打包了应用运行所需要的整个操作系统,从而保证了本地环境和云端环境的高度一致,避免了用户通过“试错”来匹配不同运行 ...

  10. [二十六]JavaIO之再回首恍然(如梦? 大悟?)

    流分类回顾 本文是JavaIO告一段落的总结帖 希望对JavaIO做一个基础性的总结(不涉及NIO) 从实现的角度进行简单的介绍 下面的这两个表格,之前出现过 数据源形式 InputStream Ou ...