前言

在面向对象语言中,接口是一个很重要的概念,它是对行为的抽象,而具体如何行动需要由类去实现。

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

​TypeScript 的核心原则之一是对值所具有的结构进行类型检查,并且只要两个对象的结构一致,属性和方法的类型一致,则它们的类型就是一致的。​ 在TypeScript里,接口的作用就是为这些类型命名和为代码或第三方代码定义契约。

简单点说,在 TypeScript中,接口是一个很重要的特性,它让 TypeScript 具备了 JavaScript 所缺少的、描述较为复杂数据结构的能力。

引入主题

其实在 JavaScript 日常开发中,很多时候都需要接口来 “规范” 程序。

假设在 JavaScript 中定义一个函数,用来获取一个用户的姓名和年龄的字符串:

function getUserInfo(user) {return `name: ${user.name}, age: ${user.age}`
}

函数调用:

getUserInfo({name: "koala", age: 18})

您可能会问,我们写 JavaScript 的时候,这个再正常不过了吧?

但请注意,如果这个 getUserInfo() 在多人开发过程中,如果它是个公共函数(多个开发者都会调用),如果不是每个人点进来看函数对应注释,可能会出现以下错误的调用:

// 1: 直接调用,不知道还需要传参数
getUserInfo() // Uncaught TypeError: Cannot read property 'name' of undefined// 2: 只传递一个参数,不知道还有其他参数
console.log(getUserInfo({name: "王佳斌"})) // name: 王佳斌, age: undefined// 3: 参数知道传递多少个,但不知键名
getUserInfo({name: "王佳斌", width: 560}) // name: 王佳斌, age: undefined// ...

由于 JavaScript 是弱类型的语言,所以 并不会对我们传入的代码进行任何的检测

😦 有些错你自己都说不清楚,但是就出了问题。


那么如何解决呢?有请 Typescript 接口登场。

创建接口

指定的接口名称,最好与普通变量名 “有所区分” ,比如接口名首字母大写、首字母前缀(In_xxx)等。

在 Typescript 中,使用 interface 关键字来定义一个接口,其中 name 就是接口名称。

interface name {}

基础使用

Typescript 接口可以规定函数的 “形状”,也可以规定变量的 “形状”,下面有两个示例。

以下 JavaScript 例子(前面已经提到了,忘记的话往前翻):

function getUserInfo(user) {return `name: ${user.name}, age: ${user.age}`
}

这个所存在的问题大家已经知道了,下面用 Typescript 接口进行函数重构。

// 规定"形状"
interface Info {name: string;age: number;
}// 函数(冒号后跟上 "接口名")
function getUserInfo({ name, age }: Info) {return `name: ${name}, age: ${age}`
}// 正常都传递
console.log(getUserInfo({ name: '王佳斌', age: 123 }))
// 结果OK:"name: 王佳斌, age: 123" // 少传递一个
console.log(getUserInfo({ name: '王佳斌' }))
// Property 'age' is missing in type '{ name: string; }' but required in type 'Info'.
// 类型“{name:string;}”中缺少属性“age”,但类型“Info”中需要该属性。// 都不传递
console.log(getUserInfo())
// Expected 1 arguments, but got 0.
// 应为1个参数,但得到了0个。

你看,这些都是在编写代码时 TypeScript 提示的错误信息,这样就避免了在使用函数的时候传入不正确的参数。

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


另外,接口还可以被变量所使用(继承接口的 “形状”),如下代码所示:

// 规定"形状"
interface Info {name: string;age: number;
}// 变量 "继承" 接口
const student: Info = {name: '小王',age: 15
}// 测试变量
console.log(student)//{"name": "小王", "age": 15}// 错误用法(比如写一个 "Info" 接口不存在的参数)
const err: Info = {a: 1
}
// Object literal may only specify known properties, and 'a' does not exist in type 'Info'.
// 对象文字只能指定已知的财产,类型“Info”中不存在“a”。

可选属性

当然,TypeScript 中也允许不 “必传” 某些参数,有这个字段就做处理,没有就忽略。

如下代码所示,message 参数可以不传递。

// 使用 "?" 表示此参数非必传
interface Log {message?: string;
}// 函数
function print({ message }: Log) {console.log(message || '该参数没有传递~')
}// 传递参数
print({ message: 'hello' }) //"hello" // 不传递
print({}) //"该参数没有传递~" 

很好理解。

只读属性

TypeScript 支持将某些参数设置为 “只读”,用于限制只能在对象刚刚创建的时候修改其值,后续无法再修改。

如下代码所示,age 参数不可后期修改。

// 使用 "readonly" 关键字表示此参数"只读"
interface Info {name: string;readonly age: number;
}// 创建变量("age"只能初始的时候赋值一次)
const student: Info = {name: '小王',age: 15
}// 测试修改只读属性 "age"
student.age = 50
// Cannot assign to 'age' because it is a read-only property.
// 无法分配给“age”,因为它是只读属性。

此外 TypeScript 还提供了 ReadonlyArray<T> 类型,它与 Array<T> 相似,只是把所有可变方法去掉了,因此可以确保数组创建后再也不能被修改。

// 创建一个 "绝对不可修改" 的数组(number类型)
let arr: ReadonlyArray<number> = [1, 2, 3, 4]// 测试赋值
arr[0] = 10
// Index signature in type 'readonly number[]' only permits reading.
// 类型为“只读数字[]”的索引签名只允许读取。// 测试添加数组项
arr.push(5)
// Property 'push' does not exist on type 'readonly number[]'.
// 类型“只读数字[]”上不存在属性“push”。// 测试赋值数组长度
arr.length = 99
// Cannot assign to 'length' because it is a read-only property.
// 无法分配给“length”,因为它是只读属性。

任意属性

有时候我们希望一个接口中除了包含必选和可选属性之外,还允许有其他的任意属性,这时我们可以使用 索引签名 的形式来满足上述要求。

如下代码所示,除了 name 必传外,后面你可以随意传递参数。

// 使用 "[propName: string]: any" 支持任意类型
interface Person {name: string;[propName: string]: any;
}// 只传递必填,其他参数不要
const a: Person = { name: '小王' }
console.log(a) //{"name": "小王"}// 传递必填,其他参数随意传递
const b: Person = { name: '小王', age: 15, sex: '男' }
console.log(b) //{"name": "小王", "age": 15, "sex": "男"}

很好理解。

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【硬件-笔试面试题-92】硬件/电子工程师,笔试面试题(知识点:米勒效应,米勒平台)

题目汇总版--链接&#xff1a; 【硬件-笔试面试题】硬件/电子工程师&#xff0c;笔试面试题汇总版&#xff0c;持续更新学习&#xff0c;加油&#xff01;&#xff01;&#xff01;-CSDN博客 【硬件-笔试面试题-92】硬件/电子工程师&#xff0c;笔试面试题&#xff08;知识点…

C语言深度入门系列:第十一篇 - 动态内存管理与数据结构:程序世界的高效算法大师

C语言深度入门系列&#xff1a;第十一篇 - 动态内存管理与数据结构&#xff1a;程序世界的高效算法大师 本章目标 本章将深入探讨C语言中的动态内存管理和经典数据结构实现&#xff0c;这是从基础编程迈向算法工程师的关键一步。您将掌握内存的精确控制、理解各种数据结构的本质…

Go 语言开发环境安装与 GOPROXY 镜像配置(含依赖管理与版本切换技巧)

在国内搭建 Go 开发环境的最大障碍不是“怎么装”&#xff0c;而是“下不动”。本文是我在多台 Windows / macOS / Linux 机器上踩坑后的整合笔记&#xff1a;用最稳妥的安装方式 合理的镜像配置 一套通吃的依赖/版本管理流程&#xff0c;把速度、稳定性和可维护性一次性解决…

崔传波教授:以科技与人文之光,点亮近视患者的清晰视界‌

崔传波教授&#xff1a;以科技与人文之光&#xff0c;点亮近视患者的清晰视界‌在临沂新益民眼科医院&#xff0c;有这样一位眼科医师——他不仅是近视矫正领域的专家&#xff0c;更是“金视青春之光手术”的研发倡导者。‌崔传波教授‌以其深厚的学术功底、创新的技术理念和以…

如何写过滤条件wrapper的使用

模糊查询 &#xff1a;功能是&#xff1a;查询 WORK_NUM 字段包含 ${workOrder.workNum} 的记录。<if test"workOrder.workNum ! null and workOrder.workNum ! ">and b.WORK_NUM like CONCAT(%,CONCAT(#{workOrder.workNum},%)) </if>一、比较条件方法示…

【Spring Boot 报错已解决】彻底解决 “Main method not found in class com.xxx.Application” 报错

文章目录引言一、问题描述1.1 报错示例1.2 报错分析1.3 解决思路二、解决方法2.1 方法一&#xff1a;添加标准的main方法2.2 方法二&#xff1a;检查main方法的定义是否规范2.3 方法三&#xff1a;检查主类的位置是否正确2.4 方法四&#xff1a;重新构建项目并清理缓存三、其他…

配置自签证书多域名的动态网站+部署http的repo仓库+基于nfs与yum仓库的http部署

1.配置自签证书多域名的动态网站1.1配置自签证书1.1.1配置仓库[rootapache ~]# vim /etc/yum.repos.d/epel.repo [epel] nameepel baseurlhttps://mirrors.aliyun.com/epel/9/Everything/x86_64/ gpgcheck0 1.1.2安装easy-rsa工具(用于生成和…

【开题答辩全过程】以 12306候补购票服务系统为例,包含答辩的问题和答案

个人简介一名14年经验的资深毕设内行人&#xff0c;语言擅长Java、php、微信小程序、Python、Golang、安卓Android等开发项目包括大数据、深度学习、网站、小程序、安卓、算法。平常会做一些项目定制化开发、代码讲解、答辩教学、文档编写、也懂一些降重方面的技巧。感谢大家的…

计算机毕业设计 基于深度学习的酒店评论文本情感分析研究 Python毕业设计项目 Hadoop毕业设计选题 机器学习选题【附源码+文档报告+安装调试】

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python、大数据、人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&…

嵌入式第五十二天(GIC,协处理器,异常向量表)

一.GICGIC&#xff08;Generic Interrupt Controller&#xff0c;通用中断控制器&#xff09; 是ARM架构中管理系统中断的核心组件&#xff0c;负责接收、优先级排序、分发中断信号给处理器核心。其核心功能和关键版本如下&#xff1a;核心功能1. 中断接收与分发&#xff1a;接…

基于hiprint的票据定位打印系统开发实践

基于hiprint的票据定位打印系统开发实践 在日常的Web开发中&#xff0c;我们经常需要实现打印功能&#xff0c;特别是对于票据、标签等需要精确排版的打印需求。今天我将分享一个基于hiprint插件实现的票据定位打印系统&#xff0c;重点介绍如何实现单行打印、批量打印以及金额…

Android ScrollView嵌套RecyclerView 导致RecyclerView数据展示不全问题

Android RecyclerView 数据展示不全问题&#xff08;ScrollView→NestedScrollView 修复&#xff09; 一、问题核心现象 布局初始结构&#xff1a;外层用ScrollView包裹包含两个CustomBlogCardView&#xff08;内部均含RecyclerView&#xff09;的LinearLayout。 异常表现&…

AI助力数学学习,轻松掌握知识点!

小伙伴们&#xff0c;今天我们来利用AI辅助数学学习&#xff0c;将数学题目提交给AI,经过分析后给出相应的解题思路和知识点分析。现在有了AI这个"智能小老师"&#xff0c;学习变得更轻松&#xff01;只需把题目交给它&#xff0c;AI就能快速分析题目类型&#xff0c…

AI-调查研究-76-具身智能 当机器人走进生活:具身智能对就业与社会结构的深远影响

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; AI炼丹日志-31- 千呼万唤始出来 GPT-5 发布&#xff01;“快的…

机器学习、深度学习

卷积神经网络&#xff08;CNN&#xff09;vs. 循环神经网络&#xff08;RNN&#xff09;vs. Transformer 一文带你搞懂 AI Agent 开发利器&#xff1a;LangGraph 与 LangChain 区别 大语言模型&#xff1a;基于LLM的应用开发框架「LangChain」最全指南

SQL语句执行时间太慢,有什么优化措施?以及衍生的相关问题

SQL语句执行时间太慢&#xff0c;有什么优化措施&#xff1f; 可以从四个方面进行&#xff1a; 第一个是查询是否添加了索引 如果没有的话&#xff0c;为查询字段添加索引&#xff0c; 还有是否存在让索引失效的场景&#xff0c;像是没有遵循最左前缀&#xff0c;进行了一些…

QtConcurrent应用解析

目录 对比传统线程 1. QtConcurrent::run() —— 异步运行函数 2.QtConcurrent::mapped() —— 并行转换 3. QtConcurrent::filter() —— 并行过滤 4. QtConcurrent::run() QFutureWatcher —— UI 异步更新 5.线程池配置 QtConcurrent 是 Qt 框架提供的一个 高级并发编…

大疆图传十公里原理:无人机图传技术解析

大疆图传系统的核心在于把发射端的能量、机载接收的灵敏度、以及环境中的衰减因素&#xff0c;进行科学的预算与动态的修正。简单的说&#xff0c;就是通过精准的链路预算来确保在最坏环境下仍有可用的信号空间。发射功率、天线增益、空中与地面的路径损耗、接收端的噪声底线等…

jmeter 带函数压测脚本

包含时间戳获取、md5值计算、随机字符串获取<?xml version"1.0" encoding"UTF-8"?> <jmeterTestPlan version"1.2" properties"5.0" jmeter"5.6.3"><hashTree><TestPlan guiclass"TestPlanGui&…

鸿蒙app日志存储

app的pid获取 import process from @ohos.process;@Entry @Component struct MainAbility {aboutToAppear(): void {console.log(this.TAG,"pid: "+process.pid)}} 获取本应用日志 在Android中可以使用logcat --pid xxxx 获取特定进程xxxx的打印日志 在鸿蒙中也有…