7、如何使用接口?

news2024/12/25 8:56:11

1、基本用法

        我们需要定义这样一个函数,参数是一个对象,里面包含两个字段:firstName 和 lastName,也就是英文的名和姓,然后返回一个拼接后的完整名字。来看下函数的定义:

// 注:这段代码为纯JavaScript代码,请在JavaScript开发环境编写下面代码,在TypeScript环境会报一些类型错误
const getFullName = ({ firstName, lastName }) => {
  return `${firstName} ${lastName}`;
};

//使用时传入参数:
getFullName({
  firstName: "Lison",
  lastName: "Li"
}); // => 'Lison Li'

//没有问题,我们得到了拼接后的完整名字,但是使用这个函数的人如果传入一些不是很理想的参数时,就会导致各种结果:
getFullName(); // Uncaught TypeError: Cannot destructure property `a` of 'undefined' or 'null'.
getFullName({ age: 18, phone: "13312345678" }); // 'undefined undefined'
getFullName({ firstName: "Lison" }); // 'Lison undefined'

        这些都是我们不想要的,在开发时难免会传入错误的参数,所以 TypeScript 能够帮我们在编译阶段就检测到这些错误。我们来完善下这个函数的定义:

const getFullName = ({
  firstName,
  lastName,
}: { // 指定这个参数的类型,因为他是一个对象,所以这里来指定对象中每个字段的类型
  firstName: string; // 指定属性名为firstName和lastName的字段的属性值必须为string类型
  lastName: string;
}) => {
  return `${firstName} ${lastName}`;
};

        我们通过对象字面量的形式去限定我们传入的这个对象的结构,现在再来看下之前的调用会出现什么提示:

getFullName(); // 应有1个参数,但获得0个
getFullName({ age: 18, phone: 123456789 }); // 类型“{ age: number; phone: number; }”的参数不能赋给类型“{ firstName: string; lastName: string; }”的参数。
getFullName({ firstName: "Lison" }); // 缺少必要属性lastName

        这些都是在我们编写代码的时候 TypeScript 提示给我们的错误信息,这样就避免了在使用函数的时候传入不正确的参数。接下来我们使用interface来定义接口:

interface Info {
  firstName: string;
  lastName: string;
}
const getFullName = ({ firstName, lastName }: Info) =>
  `${firstName} ${lastName}`;

        注意在定义接口的时候,你不要把它理解为是在定义一个对象,而要理解为{}括号包裹的是一个代码块,里面是一条条声明语句,只不过声明的不是变量的值而是类型。声明也不用等号赋值,而是冒号指定类型。每条声明之前用换行分隔即可,或者也可以使用分号或者逗号,都是可以的。

2、可选属性

        当我们定义一些结构的时候,一些结构对于某些字段的要求是可选的,有这个字段就做处理,没有就忽略,所以针对这种情况,typescript为我们提供了可选属性。我们先定义一个描述传入蔬菜信息的句子的函数:

const getVegetables = ({ color, type }) => {
  return `A ${color ? color + " " : ""}${type}`;
};

        我们可以看到这个函数中根据传入对象中的 color 和 type 来进行描述返回一句话,color 是可选的,所以我们可以给接口设置可选属性,在属性名后面加个?即可:

interface Vegetables {
  color?: string;
  type: string;
}

        这里可能 tslint 会报一个警告,告诉我们接口应该以大写的i开头,如果你想关闭这条规则,可以在 tslint.json 的 rules 里添加"interface-name": [true, “never-prefix”]来关闭。

3、多余属性检查

getVegetables({
  type: "tomato",
  size: "big" // 'size'不在类型'Vegetables'中
});

        我们看到,传入的参数没有 color 属性,但也没有错误,因为它是可选属性。但是我们多传入了一个 size 属性,这同样会报错,TypeScript 会告诉你,接口上不存在你多余的这个属性。只要接口中没有定义这个属性,就会报错,但如果你定义了可选属性 size,那么上面的例子就不会报错。

        这里可能 tslint 会报一个警告,告诉我们属性名没有按开头字母顺序排列属性列表,如果你想关闭这条规则,可以在 tslint.json 的 rules 里添加"object-literal-sort-keys": [false]来关闭。

4、绕开多余属性检查

        有时我们并不希望 TypeScript 这么严格地对我们的数据进行检查,比如我们只需要保证传入getVegetables的对象有type属性就可以了,至于实际使用的时候传入对象有没有多余的属性,多余属性的属性值是什么类型,这些都无所谓,那就需要绕开多余属性检查,有如下三个方法:

 4.1、使用断言类型

        我们在基础类型中讲过,类型断言就是用来明确告诉 TypeScript,我们已经自行进行了检查,确保这个类型没有问题,希望 TypeScript 对此不进行检查,所以最简单的方式就是使用类型断言:

interface Vegetables {
  color?: string;
  type: string;
}
const getVegetables = ({ color, type }: Vegetables) => {
  return `A ${color ? color + " " : ""}${type}`;
};
getVegetables({
  type: "tomato",
  size: 12,
  price: 1.2
} as Vegetables);

4.2、添加索引签名

更好的方式是添加字符串索引签名,索引签名我们会在后面讲解,先来看怎么实现:

interface Vegetables {
  color: string;
  type: string;
  [prop: string]: any;
}
const getVegetables = ({ color, type }: Vegetables) => {
  return `A ${color ? color + " " : ""}${type}`;
};
getVegetables({
  color: "red",
  type: "tomato",
  size: 12,
  price: 1.2
});

4.3、利用类型兼容性

这种方法现在还不是很好理解,也是不推荐使用的,先来看写法:

interface Vegetables {
  type: string;
}
const getVegetables = ({ type }: Vegetables) => {
  return `A ${type}`;
};

const option = { type: "tomato", size: 12 };
getVegetables(option);

        面这种方法完美通过检查,我们将对象字面量赋给一个变量option,然后getVegetables传入 option,这时没有报错。是因为直接将对象字面量传入函数,和先赋给变量再将变量传入函数,这两种检查机制是不一样的,后者是因为类型兼容性。我们后面会有专门一节来讲类型兼容性。简单地来说:如果 b 要赋值给 a,那要求 b 至少需要与 a 有相同的属性,多了无所谓。

        在上面这个例子中,option的类型应该是Vegetables类型,对象{ type: ‘tomato’, size: 12 }要赋值给 optionoption中所有的属性在这个对象字面量中都有,所以这个对象的类型和option(也就是Vegetables类型)是兼容的,所以上面例子不会报错。如果你现在还想不明白没关系,我们还会在后面详细去讲。

4.4、只读属性

接口也可以设置只读属性,如下:

interface Role {
  readonly 0: string;
  readonly 1: string;
}

//这里我们定义了一个角色字典,有 0 和 1 两种角色 id。下面我们定义一个实际的角色  数据,然后来试图修改一下它的值:
const role: Role = {
  0: "super_admin",
  1: "admin"
};
role[1] = "super_admin"; // Cannot assign to '0' because it is a read-only property

        我们看到 TypeScript 告诉我们不能分配给索引0,因为它是只读属性。设置一个值只读,我们是否想到ES6里定义常量的关键字const?使用const定义的常量定义之后不能再修改,这有点只读的意思。那readonlyconst在使用时该如何选择呢?这主要看你这个值的用途,如果是定义一个常量,那用const,如果这个值是作为对象的属性,那请用readonly。我们来看下面的代码:

const NAME: string = "Lison";
NAME = "Haha"; // Uncaught TypeError: Assignment to constant variable

const obj = {
  name: "lison"
};
obj.name = "Haha";

interface Info {
  readonly name: string;
}
const info: Info = {
  name: "Lison"
};
info["name"] = "Haha"; // Cannot assign to 'name' because it is a read-only property

        我们可以看到上面使用const定义的常量NAME定义之后再修改会报错,但是如果使用const定义一个对象,然后修改对象里属性的值是不会报错的。所以如果我们要保证对象的属性值不可修改,需要使用readonly

5、函数类型

接口可以描述普通对象,还可以描述函数类型,我们先看写法:

interface AddFunc {
  (num1: number, num2: number): number;
}

        这里我们定义了一个AddFunc结构,这个结构要求实现这个结构的值,必须包含一个和结构里定义的函数一样参数、一样返回值的方法,或者这个值就是符合这个函数要求的函数。我们管花括号里包着的内容为调用签名,它由带有参数类型的参数列表和返回值类型组成。后面学到类型别名一节时我们还会学习其他写法。来看下如何使用:

const add: AddFunc = (n1, n2) => n1 + n2;
const join: AddFunc = (n1, n2) => `${n1} ${n2}`; // 不能将类型'string'分配给类型'number'
add("a", 2); // 类型'string'的参数不能赋给类型'number'的参数

        上面我们定义的add函数接收两个数值类型的参数,返回的结果也是数值类型,所以没有问题。而join函数参数类型没错,但是返回的是字符串,所以会报错。而当我们调用add函数时,传入的参数如果和接口定义的类型不一致,也会报错。你应该注意到了,实际定义函数的时候,名字是无需和接口中参数名相同的,只需要位置对应即可。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/458815.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【致敬未来的攻城狮计划】— 连续打卡第十二天:FSP固件库开发按键输入检测控制LED灯闪烁。

系列文章目录 1.连续打卡第一天:提前对CPK_RA2E1是瑞萨RA系列开发板的初体验,了解一下 2.开发环境的选择和调试(从零开始,加油) 3.欲速则不达,今天是对RA2E1 基础知识的补充学习。 4.e2 studio 使用教程 5.…

关于 OpenShift(OKD) 网络 Service、Routes的一些笔记

写在前面 参加考试,分享一些学习 OpenShift 的笔记博文内容为 OpenShift 网络相关组件 Service、Routes 很浅的一些认识学习环境为 openshift v3 的版本,有些旧这里如果专门学习 openshift ,建议学习 v4 版本理解不足小伙伴帮忙指正 傍晚时分…

轻量级服务器nginx:反向代理的具体配置

系列文章目录 例如:第一章 Python 机器学习入门之pandas的使用 反向代理和负载均衡 系列文章目录一 反向代理1.正向代理2.反向代理 二 反向代理的实际部署1.配置tomcat2.配置host,nginx反向代理的配置三 结果展示四 总结 一 反向代理 1.正向代理 我们…

通过docker发布项目

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言例如:docker项目的发布方式 [docker发布的参考链接](https://www.cnblogs.com/emperorking/articles/11244253.html) 一、docker是什么?…

Django框架之自定义管理页面

Django框架Admin站点管理一些默认的显示和功能包括语言都可以自定义设置处理,以贴近我们的实际业务。 属性说明 列表页属性 配置文件myapp/admin.py from django.contrib import admin from .models import Grades, Students# Register your models here.# 注册班…

收废品小程序开发中的常见问题及解决方法

常见问题 1. 用户界面设计 小程序的用户界面设计至关重要。设计师需要在用户界面中提供清晰的指示,以便用户可以轻松地找到他们需要的功能。同时,设计师还需要确保用户界面的整体风格与公司的品牌形象相符。 2. 功能开发 开发小程序的功能需要考虑到…

深入学习RabbitMQ五种模式(一)

1.安装erlang 下载otp_win64_25.3.exe https://www.erlang.org/downloads erlang安装完成,需要配置erlang环境变量 ERLANG_HOMEE:\software\Erlang OTPPATH%PATH%;%ERLANG_HOME%\bin; 2.安装RabbitMQ 下载rabbitmq-server-3.11.13.exe https://www.rabbitmq.com/dow…

交叉验证之KFold和StratifiedKFold的使用(附案例实战)

🤵‍♂️ 个人主页:艾派森的个人主页 ✍🏻作者简介:Python学习者 🐋 希望大家多多支持,我们一起进步!😄 如果文章对你有帮助的话, 欢迎评论 💬点赞&#x1f4…

力扣---LeetCode88. 合并两个有序数组

文章目录 前言88. 合并两个有序数组链接:方法一:三指针(后插)1.2 代码:1.2 流程图:方法二:开辟新空间2.1 代码:2.2 流程图:2.3 注意: 总结 前言 “或许你并不熠熠生辉甚至有点木讷但…

POSTGRESQL COPY 命令原理与加速数据 导入提高速度200%以上

开头还是介绍一下群,如果感兴趣polardb ,mongodb ,mysql ,postgresql ,redis 等有问题,有需求都可以加群群内有各大数据库行业大咖,CTO,可以解决你的问题。加群请联系 liuaustin3 ,在新加的朋友会分到2群(共…

vue2+vue3——107+

vue2vue3——107 vue2 Vuex工作原理图【23:54】vue2 搭建Vuex环境【26:40】插入 话题npm i vue3 store / index.js修改 vue2 求和案例_vuex版【22:39】vue2 vuex开发者工具的使用【23:21】vue2 getters配置项【07:55】vue2 mapState与mapGetters【25:20】vue2 mapActions与mapM…

egg3.0连接egg-mongoose操作数据库,删除一条数据、批量删除数据

删除一条数据 定义service app\service\role.js async delItem() {const { ctx } this;let results;await ctx.model.Role.deleteOne({ name: test-S3 }).then(res > {console.log(results-del-success, res);results res?.deletedCount > 0;}).catch(err > {con…

系统分析师之软件工程(十二)

目录 一、 软件开发生命周期 1.1 开发阶段工作细分 二、软件开发模型 2.1 瀑布模型 2.2 原型模型 2.3 增量模型与螺旋模型 2.4 V模型 2.5 喷泉模型 2.6 快速应用开发模型RAD 2.7 构件主装模型 2.8 统一过程 2.9 敏捷方法 三、逆向工程 四、净室软件工程 一、 软件…

为何C语言的函数调用要用到堆栈,而汇编却不需要自定义栈

一 ≠ 汇编不需要堆栈 汇编中一般不初始化,也就是直接使用系统的堆栈而已,自己定义堆栈还是要初始化的。 之前看了很多关于uboot的分析,其中就有说要为C语言的运行,准备好堆栈。 而自己在Uboot的start.S汇编代码中&#xff0c…

crm-day04 分页查询市场活动,刷新市场活动列表

分页插件 分页这个组件前端要写也很麻烦&#xff0c;而且与业务逻辑代码无关&#xff0c;因此我们引入一个分页查询的插件。 进行jsp测试 三大步骤&#xff1a; 1、引入相关的包 2、创建容器来保存插件的运行结果 容器是<input typetext/>或者div。 3、容器加载完成后&a…

猫猫与主人

时间限制&#xff1a;C/C 1秒&#xff0c;其他语言2秒 空间限制&#xff1a;C/C 262144K&#xff0c;其他语言524288K 64bit IO Format: %lld 对猫猫按照友善值进行排序 对主人按照期望友善值进行排序 就可以找到能收养猫猫的主人 对主人的友善值取一个max最后跟猫猫的期望友…

用大佬开发的模板做了“智慧水务”,终于可以和老板谈加薪喽!

为什么各个行业要进行数字化转型&#xff1f; 其实很好理解&#xff0c;这其中很大一部分属于传统行业&#xff0c;以往运营方式较为粗放&#xff0c;信息标准化程度偏低&#xff0c;但同时也意味着数字化的历史包袱轻&#xff0c;此时跟上潮流进行数字化转型&#xff0c;有利于…

美颜SDK的性能测试和优化方案

美颜SDK作为美颜相机、短视频等应用的核心技术之一&#xff0c;对于提升用户体验和增加应用商业价值起到了至关重要的作用。然而&#xff0c;如何对美颜SDK进行性能测试和优化&#xff0c;成为了广大应用开发者们所面临的一大难题。很多开发者也曾经向小编提起过应该如何着手优…

nodejs+python+php+springboot+vue 校园安全车辆人员出入安全管理系统

拟开发的校园安全管理系统通过测试,确保在最大负载的情况下稳定运转,各个模块工作正常,具有较高的可用性。系统整体界面简洁美观,用户使用简单,满足用户需要。在因特网发展迅猛的当今社会,校园安全管理系统必然会成为在数字信息化建设的一个重要方面。 本文阐述了开发的校园安全…

马斯克要告微软 拒绝AI训练“白嫖”数据

“现在是诉讼时间。”4月20日&#xff0c;推特被微软踢出其数字营销平台后&#xff0c;新掌门人马斯克立马发推回击称&#xff0c;微软用推特的数据做“非法训练”。这一怼&#xff0c;直接揭开了AI大模型开发商与数据源的利益之争。 此前&#xff0c;在线社区论坛Reddit与程序…