TypeScript 学习笔记 — 接口的使用(六)
在 TS 中,使用接口(Interfaces)来定义对象的类型。可用于对类的一部分行为进行抽象以外,也常用于对对象的形状(Shape)进行描述。(接口都是抽象的,接口中不能含有具体的实现逻辑)
一.函数接口参数
const fullName = ({ firstName, lastName }: { firstName: string; lastName: string }): string => {
return firstName + lastName;
};
// 可以约束函数中的参数,但是类型无法复用,可以通过接口进行描述
interface IFullName {
firstName: string;
lastName: string;
}
const fullName = ({ firstName, lastName }: IFullName): string => {
return firstName + lastName;
};
getFullName({ firstname: "j", lastname: "w" });
二.函数类型接口
通过接口限制函数的参数类型和返回值类型
interface IFullName {
firstName: string;
lastName: string;
}
interface IFn {
(obj: IFullName): string;
}
const fullName: IFn = ({ firstName, lastName }) => {
return firstName + lastName;
};
三.函数混合类型
interface ICounter {
(): number; // 限制函数类型
count: 0; // 限制函数上的属性
}
let fn: any = () => {
return fn.count++;
};
fn.count = 0;
let counter: ICounter = fn;
console.log(counter());
console.log(counter());
四.对象接口(最常用)
对象接口用来描述对象的形状结构,定义一个接口 Person(接口一般首字母大写),定义一个变量 tom 类型是 Person。这样就约束了 tom 的形状必须和接口 Person 一致。
interface Person {
name: string;
age: number;
}
let p1: Person = {
name: "Tom",
age: 25,
};
确定属性
确定属性:赋值时,定义的变量的形状必须与接口形状保持一致。变量的属性比接口少或多属性都是不允许的:
interface Person {
name: string;
age: number;
}
let p1: Person = {
// 类型中缺少属性 "age",但类型 "Person" 中需要该属性。
name: "Tom",
};
let p2: Person = {
// 多余 gender 属性
name: "Tom",
age: 25,
gender: "male",
};
可选属性
可选属性:是指该属性可以不存在。有时不需要完全匹配一个接口时,可以用可选属性,但此时仍然不允许添加未定义的属性
interface Person {
name: string;
age?: number;
}
let p1: Person = {
// 编译通过
name: "Tom",
};
let p2: Person = {
// 编译通过
name: "Tom",
age: 25,
};
let p3: Person = {
// 多余 gender 属性
name: "Tom",
age: 25,
gender: "male",
};
其他三种不太常用的 实现可选参数的方法:
- 断言案例:
interface IVeg {
color: string;
taste: string;
size: number;
}
let veg: IVeg = {
color: "red",
taste: "sour",
size: 10,
xx: 1,
} as IVeg;
- 同名接口案例:
interface IVeg {
color: string;
taste: string;
size: number;
}
interface IVeg {
xx: number;
}
let veg: IVeg = {
color: "red",
taste: "sour",
size: 10,
xx: 1,
};
- 基于当前类型,声明一个新的类型,实现参数的可选
interface IVeg {
color: string;
taste: string;
size: number;
}
interface IVegWithX extends IVeg {
xx?: number;
}
let veg: IVegWithX = {
// 此时变量的类型 为新创建的类型
color: "red",
taste: "sour",
size: 10,
xx: 1,
};
任意属性
任意属性:允许一个接口有任意的属性,使用 [propName: string] 定义了任意属性的属性名取 string 类型的值。属性值为任意值 any,
任意属性对必填属性做限制,其余的可以随意增减
interface Person {
name: string;
age?: number;
// 对象的key 可以有三种类型 string number symbol
[propName: string]: any;
}
let p1: Person = {
name: "Tom",
gender: "male",
[Symbol()]: "xxx",
};
注意:一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集:
例一:任意属性的类型是 string,但是可选属性 age 的值却是 number,number 不是 string 的子属性,所以会报错。
interface Person {
name: string;
age?: number;
[propName: string]: string;
}
let p1: Person = {
// 属性“age”与索引签名不兼容。不能将类型“number”分配给类型“string”。
name: "Tom",
age: 25,
gender: "male",
};
例二:一个接口中只能定义一个任意属性。如果接口中有多个类型的属性,可以在任意属性中使用联合类型:
interface Person {
name: string;
age?: number;
[propName: string]: string | number;
}
let p1: Person = {
// 编译通过
name: "Tom",
age: 25,
gender: "male",
year: 2021,
};
只读属性
对象中的一些字段只能在创建时被赋值,可以使用 **readonly **定义只读属性:
例一:使用 readonly 定义的属性 id 初始化后,又被重新赋值,所以会报错。
interface Person {
readonly id: number;
name: string;
age?: number;
[propName: string]: any;
}
let p1: Person = {
id: 89757,
name: "Tom",
gender: "male",
};
p1.id = 9527; // 无法分配到 "id" ,因为它是只读属性。
例二:只读的约束存在于第一次给对象赋值的时候,而不是第一次给只读属性赋值时:
interface Person {
readonly id: number;
name: string;
age?: number;
[propName: string]: any;
}
let p2: Person = {
// 缺少属性 "id",但类型 "Person" 中需要该属性。
// 第一次给对象赋值
name: "Tom",
gender: "male",
};
p2.id = 89757;
可索引接口
可索引接口可以用于标识数字索引、数组
interface IArr {
[key: number]: any;
}
const obj: IArr = {
0: 100,
"1": 10, // 数字字符串可以转为数字,所以编译会通过
2: 200,
};
let arr: IArr = [1, "d", "c"];
索引访问符
通过索引访问符来访问接口中的属性类型
interface Person {
name: string;
age: string;
address: {
num: 316;
};
[key: string]: any; // 如果写了任意类型,则取出的val 就是任意类型 any
}
type PersonName = Person["name"];
type PersonNum = Person["address"]["num"]; // 316
type PropTypeUnion = keyof Person; // 取key name | age | address
let xxx: PropTypeUnion; // 取key name | age | address
type PropTypeValueUnion = Person[keyof Person]; // 取值 string | {num:316}
// 案例:
{
interface Person {
name: string;
age: string;
address: {
num: 316;
};
[key: string]: any;
}
// 如果写了任意类型,则取出的val 就是任意类型 any
type PropTypeValueUnion = Person[keyof Person]; // 取值 any
}
类接口
描述类中的属性和方法。一个类可以实现多个接口,在类中必须实现接口中的方法和属性
interface Speakable {
name: string;
speak(): void;
}
interface SpeakChinese {
speakChinese(): void;
}
class Speak implements Speakable, SpeakChinese {
name!: string;
speak() {}
speakChinese() {}
}
接口继承
interface Speakable {
name: string;
speak(): void;
}
interface SpeakChinese {
speakChinese(): void;
}
interface SpeakEnglish extends Speakable, SpeakChinese {
speakEnglish(): void;
}
// 可以实现多个类型
class Speak implements SpeakEnglish {
name!: string;
speak(): void {
console.log("speak");
}
speakChinese(): void {
console.log("speakChinese");
}
speakEnglish(): void {
console.log("speakEnglish");
}
}
构造函数类型
interface Clazz {
new (): any;
}
function createClass(target: Clazz) {
return new target(); // 传入的是一个构造函数
}
class Animal {}
let r = createClass(Animal);
但是上述代码无法标识返回值类型,此时需要引入泛型的概念,在下一章节会详细学习泛型的概念及使用方法,
new() 表示当前是一个构造函数类型。 在使用 createClass 时动态传入类型。
泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。
泛型类似于函数的参数 , 泛型的声明一般采用一个大写字母来表示,
其中 T 代表 Type,在定义泛型时通常用作第一个类型变量名称。但实际上 T 可以用任何有效名称代替
interface Clazz<T> {
new (): T;
}
function createClass<T>(target: Clazz<T>): T {
return new target();
}
class Animal {}
let r = createClass(Animal);
type 和 interface 的区别
interface 通常描述 对象、类的结构比较多,可以被扩展和实现、继承、混合类型,能重名
type 描述函数的签名、联合类型、工具类型、映射条件类型,不能重名
TypeScript 学习笔记 — 接口的使用(六)的更多相关文章
- Typescript 学习笔记六:接口
中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...
- Typescript 学习笔记七:泛型
中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...
- Typescript 学习笔记五:类
中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...
- Typescript 学习笔记四:回忆ES5 中的类
中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...
- Typescript 学习笔记二:数据类型
中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...
- Typescript 学习笔记三:函数
中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...
- Typescript 学习笔记一:介绍、安装、编译
前言 整理了一下 Typescript 的学习笔记,方便后期遗忘某个知识点的时候,快速回忆. 为了避免凌乱,用 gitbook 结合 marketdown 整理的. github地址是:ts-gitb ...
- TypeScript学习笔记(八):1.5版本之后的模块和命名空间
我之前有写过TS1.5版本之前的“模块”的笔记:TypeScript学习笔记(七):模块 但是TS这里的模块和在ECMAScript 2015里的模块(即JS原生支持了模块的概念)概率出现了混淆,所以 ...
- Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十六章:实例化和截头锥体裁切
原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十六章:实例化和截头锥体裁切 代码工程地址: https://git ...
- typescript学习笔记(三)---接口
关于第二章的学习笔记是变量声明. 接口:TypeScript的核心原则之一是对值所具有的结构进行类型检查. 它有时被称做“鸭式辨型法”或“结构性子类型化”. 在TypeScript里,接口的作用就是为 ...
随机推荐
- 倒计时7天!AIRIOT新品发布会,6月6日北京见。
随着物联网.大数据.AI技术的成熟和演进,智能物联网技术正在加速.深入渗透至各行业应用. AIRIOT物联网平台作为赋能数字经济发展和产业转型的数字基座,由航天科技控股集团股份有限公司(股票代码:00 ...
- Android 13 - Media框架(2)- Demo App与MediaPlayer Api了解
关注公众号免费阅读全文,进入音视频开发技术分享群! 尝试用MediaPlayer写了一个播放demo,实现了网络流和本地流的播放.由于本人对app开发一窍不通,所以demo中很多内容是边查资料边写的, ...
- nginx日志缓存open_log_file_cache
nginx日志缓存,提升磁盘性能 将多个日志进行积累,达到一定量级后写入到磁盘,可以减少磁盘旋转,从而降低磁盘i/o,提升nginx能效 语法: access_log path access_log ...
- UILable在Autolayout模式下面自动调节字体大小
一.需求 固定UILabel的宽度大小在一定范围,内容能够自动伸缩 二.实施 首先加好约束: 约束加好之后,需要设置好Autoshrink属性,包括Line break.BaseLine.以及缩小字体 ...
- php分页查询 子查询
分页查询 将查询结果只显示一部分 通过两个参数:参数1 起始数据的索引下标 参 ...
- 为什么魂斗罗只有128KB却能实现那么长的剧情有答案了
PPU 首发公号:Rand_cs 本文继续讲述 NES 的基本原理,承接上文的 CPU,本文来讲述 PPU,较为复杂,慢慢来看.例子基本都是使用的魂斗罗,看完本文相信对那问题"为什么魂斗罗只 ...
- kettle从入门到精通 第二十八课 初识kettle-job
1.前面我们一起学习了,很多转换的知识,转换为批量的开发做铺垫,今天我们一起来学习下kettle job的知识. kettle job 常用的步骤如下图,有Start.转换.作业.成功等步骤. 2.下 ...
- oop课程4-6次作业小结
目录 (1)前言 (2)设计与分析 第四次作业(答题判题程序-4) 新增多选类 新增填空类 第五次作业(家居强电电路模拟程序-1) Element类 控制设备 开关# 分档调速器# 受控设备 白炽灯# ...
- 推荐十个优秀的ASP.NET Core第三方中间件,你用过几个?
ASP.NET Core 作为一个强大的.跨平台的.高性能的开源框架,为开发者提供了丰富的功能和灵活的扩展性.其中,中间件(Middleware)是 ASP.NET Core 架构中的核心组件之一,它 ...
- asp.net core mvc 使用quartz
参照了:https://www.cnblogs.com/dangzhensheng/p/10496278.html 1.新建任务类ReportJob.cs,这个类里就是具体任务了. using Qua ...