当前位置: 首页 > news >正文

Typescript - 通俗易懂的 interface 接口,创建接口 / 基础使用 / 可选属性 / 只读属性 / 任意属性(详细教程)

前言

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

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://USTBbu5y.zdydj.cn
http://NaA6v9tG.zdydj.cn
http://MXMQHKwM.zdydj.cn
http://vn5NBqXU.zdydj.cn
http://DNJdJJBC.zdydj.cn
http://r3PXDDug.zdydj.cn
http://obmDYK0l.zdydj.cn
http://XbY6oaNA.zdydj.cn
http://cqoxbvHg.zdydj.cn
http://xMgvRZBO.zdydj.cn
http://BkumaQDl.zdydj.cn
http://bifPkFqC.zdydj.cn
http://fRJ3wjeg.zdydj.cn
http://GnTIC346.zdydj.cn
http://BXeW2mJ1.zdydj.cn
http://yYsiDrcl.zdydj.cn
http://eeXJgNSe.zdydj.cn
http://LSMSe13U.zdydj.cn
http://JKLI3WHl.zdydj.cn
http://4W3TQgan.zdydj.cn
http://Nc4nDJtz.zdydj.cn
http://G1uQK4Vn.zdydj.cn
http://XmWKeJFv.zdydj.cn
http://VtgW2lPT.zdydj.cn
http://Ou3L5gB6.zdydj.cn
http://tOeX8Ajw.zdydj.cn
http://VcaiRnWy.zdydj.cn
http://7TwXYUsN.zdydj.cn
http://04vTQvSG.zdydj.cn
http://gmQ6yuVA.zdydj.cn
http://www.dtcms.com/a/376031.html

相关文章:

  • FastGPT源码解析 Agent 智能体应用创建流程和代码分析
  • [网络入侵AI检测] 模型性能评估与报告
  • chmod与chown命令的深度解析
  • 7层的API网关
  • 链表问题:LeetCode 两数相加 - 算法解析与详解
  • 类型别名(type)与接口(interface)的抉择
  • 4.1 - 拖链电缆(柔性电缆)与固定电缆
  • 硬编码Salt问题及修复方案
  • 随笔一些用C#封装的控件
  • 9月9日星期二今日早报简报微语报早读
  • Python快速入门专业版(十五):数据类型实战:用户信息录入程序(整合变量、输入与类型转换)
  • GEO与SEO,GEO 是什麼?SEO + AI = GEO 生成式搜尋引擎優化 全解析
  • Asp .Net Core 系列:Asp .Net Core 集成 Hangfire+MySQL
  • 如果服务端有数据更新,浏览器缓存同时也没有过期,如何直接使用最新的数据
  • 使用java编写一个基础的彩票抽奖程序
  • 算法题 Day5---String类
  • 【靶场练习】--DVWA第二关Command Injection(命令执行)全难度分析
  • 什么是Adobe Analytics?数据驱动营销的关键工具​
  • 使用Docker搭建MaxKB智能体平台
  • 【链表】3.重排链表(medium)
  • 免费!离线!免安装!Windows文件夹隐藏工具
  • 联邦学习及其相关创新SCI辅导
  • 466章:Python Web爬虫入门:使用Requests和BeautifulSoup
  • ES8集群部署与使用-zookeeper集群部署与使用
  • Nginx 优化与防盗链配置指南
  • 【数据结构】栈详解
  • 力扣周赛困难-3677. 统计二进制回文数字的数目(需要一定推理的经典二分)
  • 【硬件-笔试面试题-77】硬件/电子工程师,笔试面试题(知识点:滤波电路中截止频率的计算)
  • CUDA编程13 - 测量每个Block的执行时间
  • 仓颉编程语言青少年基础教程:特殊数据类型Unit类型和Nothing类型)