TypeScript 的 interface 接口
TypeScript 的 interface 接口
简介
interface 是对象的模板,可以看作是一种类型约定,中文译为“接口”。使用了某个模板的对象,就拥有了指定的类型结构。
interface Person {firstName: string;lastName: string;age: number;}
上面示例中,定义了一个接口Person,它指定一个对象模板,拥有三个属性firstName、lastName和age。任何实现这个接口的对象,都必须部署这三个属性,并且必须符合规定的类型。
实现该接口很简单,只要指定它作为对象的类型即可。
const p:Person = {firstName: 'John',lastName: 'Smith',age: 25};
上面示例中,变量p的类型就是接口Person,所以必须符合Person指定的结构。
方括号运算符可以取出 interface 某个属性的类型。
interface Foo {a: string;}type A = Foo['a']; // string
上面示例中,Foo['a']返回属性a的类型,所以类型A就是string。
interface 可以表示对象的各种语法,它的成员有5种形式。
- 对象属性
- 对象的属性索引
- 对象方法
- 函数
- 构造函数
(1)对象属性
interface Point {x: number;y: number;}
上面示例中,x和y都是对象的属性,分别使用冒号指定每个属性的类型。
属性之间使用分号或逗号分隔,最后一个属性结尾的分号或逗号可以省略。
如果属性是可选的,就在属性名后面加一个问号。
interface Foo {x?: string;}
如果属性是只读的,需要加上readonly修饰符。
interface A {readonly a: string;}
(2)对象的属性索引
interface A {[prop: string]: number;}
上面示例中,[prop: string]就是属性的字符串索引,表示属性名只要是字符串,都符合类型要求。
属性索引共有string、number和symbol三种类型。
一个接口中,最多只能定义一个字符串索引。字符串索引会约束该类型中所有名字为字符串的属性。
interface MyObj {[prop: string]: number;a: boolean; // 编译错误}
上面示例中,属性索引指定所有名称为字符串的属性,它们的属性值必须是数值(number)。属性a的值为布尔值就报错了。
属性的数值索引,其实是指定数组的类型。
interface A {[prop: number]: string;}const obj:A = ['a', 'b', 'c'];
上面示例中,[prop: number]表示属性名的类型是数值,所以可以用数组对变量obj赋值。
同样的,一个接口中最多只能定义一个数值索引。数值索引会约束所有名称为数值的属性。
如果一个 interface 同时定义了字符串索引和数值索引,那么数值索性必须服从于字符串索引。因为在 JavaScript 中,数值属性名最终是自动转换成字符串属性名。
interface A {[prop: string]: number;[prop: number]: string; // 报错}interface B {[prop: string]: number;[prop: number]: number; // 正确}
上面示例中,数值索引的属性值类型与字符串索引不一致,就会报错。数值索引必须兼容字符串索引的类型声明。
(3)对象的方法
对象的方法共有三种写法。
// 写法一interface A {f(x: boolean): string;}// 写法二interface B {f: (x: boolean) => string;}// 写法三interface C {f: { (x: boolean): string };}
属性名可以采用表达式,所以下面的写法也是可以的。
const f = 'f';interface A {[f](x: boolean): string;}
类型方法可以重载。
interface A {f(): number;f(x: boolean): boolean;f(x: string, y: string): string;}
interface 里面的函数重载,不需要给出实现。但是,由于对象内部定义方法时,无法使用函数重载的语法,所以需要额外在对象外部给出函数方法的实现。
interface A {f(): number;f(x: boolean): boolean;f(x: string, y: string): string;}function MyFunc(): number;function MyFunc(x: boolean): boolean;function MyFunc(x: string, y: string): string;function MyFunc(x?:boolean|string, y?:string):number|boolean|string {if (x === undefined && y === undefined) return 1;if (typeof x === 'boolean' && y === undefined) return true;if (typeof x === 'string' && typeof y === 'string') return 'hello';throw new Error('wrong parameters');}const a:A = {f: MyFunc}
上面示例中,接口A的方法f()有函数重载,需要额外定义一个函数MyFunc()实现这个重载,然后部署接口A的对象a的属性f等于函数MyFunc()就可以了。
(4)函数
interface 也可以用来声明独立的函数。
interface Add {(x:number, y:number): number;}const myAdd:Add = (x,y) => x + y;
上面示例中,接口Add声明了一个函数类型。
(5)构造函数
interface 内部可以使用new关键字,表示构造函数。
interface ErrorConstructor {new (message?: string): Error;}
上面示例中,接口ErrorConstructor内部有new命令,表示它是一个构造函数。
TypeScript 里面,构造函数特指具有constructor属性的类,详见《Class》一章。
interface 的继承
interface 可以继承其他类型,主要有下面几种情况。
interface 继承 interface
interface 可以使用extends关键字,继承其他 interface。
interface Shape {name: string;}interface Circle extends Shape {radius: number;}
上面示例中,Circle继承了Shape,所以Circle其实有两个属性name和radius。这时,Circle是子接口,Shape是父接口。
extends关键字会从继承的接口里面拷贝属性类型,这样就不必书写重复的属性。
interface 允许多重继承。
interface Style {color: string;}interface Shape {name: string;}interface Circle extends Style, Shape {radius: number;}
上面示例中,Circle同时继承了Style和Shape,所以拥有三个属性color、name和radius。
多重接口继承,实际上相当于多个父接口的合并。
如果子接口与父接口存在同名属性,那么子接口的属性会覆盖父接口的属性。注意,子接口与父接口的同名属性必须是类型兼容的,不能有冲突,否则会报错。
interface Foo {id: string;}interface Bar extends Foo {id: number; // 报错}
上面示例中,Bar继承了Foo,但是两者的同名属性id的类型不兼容,导致报错。
多重继承时,如果多个父接口存在同名属性,那么这些同名属性不能有类型冲突,否则会报错。
interface Foo {id: string;}interface Bar {id: number;}// 报错interface Baz extends Foo, Bar {type: string;}
上面示例中,Baz同时继承了Foo和Bar,但是后两者的同名属性id有类型冲突,导致报错。
interface 继承 type
interface 可以继承type命令定义的对象类型。
type Country = {name: string;capital: string;}interface CountryWithPop extends Country {population: number;}
上面示例中,CountryWithPop继承了type命令定义的Country对象,并且新增了一个population属性。
注意,如果type命令定义的类型不是对象,interface 就无法继承。
interface 继承 class
inteface 还可以继承 class,即继承该类的所有成员。关于 class 的详细解释,参见下一章。
class A {x:string = '';y():boolean {return true;}}interface B extends A {z: number}
上面示例中,B继承了A,因此B就具有属性x、y()和z。
实现B接口的对象就需要实现这些属性。
const b:B = {x: '',y: function(){ return true },z: 123}
上面示例中,对象b就实现了接口B,而接口B又继承了类A。
某些类拥有私有成员和保护成员,interface 可以继承这样的类,但是意义不大。
class A {private x: string = '';protected y: string = '';}interface B extends A {z: number}// 报错const b:B = { /* ... */ }// 报错class C implements B {// ...}
上面示例中,A有私有成员和保护成员,B继承了A,但无法用于对象,因为对象不能实现这些成员。这导致B只能用于其他 class,而这时其他 class 与A之间不构成父类和子类的关系,使得x与y无法部署。
接口合并
多个同名接口会合并成一个接口。
interface Box {height: number;width: number;}interface Box {length: number;}
上面示例中,两个Box接口会合并成一个接口,同时有height、width和length三个属性。
这样的设计主要是为了兼容 JavaScript 的行为。JavaScript 开发者常常对全局对象或者外部库,添加自己的属性和方法。那么,只要使用 interface 给出这些自定义属性和方法的类型,就能自动跟原始的 interface 合并,使得扩展外部类型非常方便。
举例来说,Web 网页开发经常会对windows对象和document对象添加自定义属性,但是 TypeScript 会报错,因为原始定义没有这些属性。解决方法就是把自定义属性写成 interface,合并进原始定义。
interface Document {foo: string;}document.foo = 'hello';
上面示例中,接口Document增加了一个自定义属性foo,从而就可以在document对象上使用自定义属性。
同名接口合并时,同一个属性如果有多个类型声明,彼此不能有类型冲突。
interface A {a: number;}interface A {a: string; // 报错}
上面示例中,接口A的属性a有两个类型声明,彼此是冲突的,导致报错。
同名接口合并时,如果同名方法有不同的类型声明,那么会发生函数重载。而且,后面的定义比前面的定义具有更高的优先级。
interface Cloner {clone(animal: Animal): Animal;}interface Cloner {clone(animal: Sheep): Sheep;}interface Cloner {clone(animal: Dog): Dog;clone(animal: Cat): Cat;}// 等同于interface Cloner {clone(animal: Dog): Dog;clone(animal: Cat): Cat;clone(animal: Sheep): Sheep;clone(animal: Animal): Animal;}
上面示例中,clone()方法有不同的类型声明,会发生函数重载。这时,越靠后的定义,优先级越高,排在函数重载的越前面。比如,clone(animal: Animal)是最先出现的类型声明,就排在函数重载的最后,属于clone()函数最后匹配的类型。
这个规则有一个例外。同名方法之中,如果有一个参数是字面量类型,字面量类型有更高的优先级。
interface A {f(x:'foo'): boolean;}interface A {f(x:any): void;}// 等同于interface A {f(x:'foo'): boolean;f(x:any): void;}
上面示例中,f()方法有一个类型声明是,参数x是字面量类型,这个类型声明的优先级最高,会排在函数重载的最前面。
一个实际的例子是 Document 对象的createElement()方法,它会根据参数的不同,而生成不同的 HTML 节点对象。
interface Document {createElement(tagName: any): Element;}interface Document {createElement(tagName: "div"): HTMLDivElement;createElement(tagName: "span"): HTMLSpanElement;}interface Document {createElement(tagName: string): HTMLElement;createElement(tagName: "canvas"): HTMLCanvasElement;}// 等同于interface Document {createElement(tagName: "canvas"): HTMLCanvasElement;createElement(tagName: "div"): HTMLDivElement;createElement(tagName: "span"): HTMLSpanElement;createElement(tagName: string): HTMLElement;createElement(tagName: any): Element;}
上面示例中,createElement()方法的函数重载,参数为字面量的类型声明会排到最前面,返回具体的 HTML 节点对象。类型越不具体的参数,排在越后面,返回通用的 HTML 节点对象。
如果两个 interface 组成的联合类型存在同名属性,那么该属性的类型也是联合类型。
interface Circle {area: bigint;}interface Rectangle {area: number;}declare const s: Circle | Rectangle;s.area; // bigint | number
上面示例中,接口Circle和Rectangle组成一个联合类型Circle | Rectangle。因此,这个联合类型的同名属性area,也是一个联合类型。
相关文章:
TypeScript 的 interface 接口
TypeScript 的 interface 接口 简介 interface 是对象的模板,可以看作是一种类型约定,中文译为“接口”。使用了某个模板的对象,就拥有了指定的类型结构。 interface Person {firstName: string;lastName: string;age: number;} 上面示例中…...
c#和form实现WebSocket在线聊天室
c#和form实现WebSocket在线聊天室 功能点 后端程序 (Program.cs)1.WebSocket 聊天服务器核心功能a.管理客户端连接(ConnectionManager 类)b.支持公聊消息广播(所有用户可见)c.支持私聊消息(通过 用户ID 格式指…...
量子代理签名:量子时代的数字授权革命
1. 量子代理签名的定义与核心原理 量子代理签名(Quantum Proxy Signature, QPS)是经典代理签名在量子信息领域的延伸,允许原始签名者(Original Signer)授权给代理签名者(Proxy Signer)代为签署文…...
「Unity3D」TextMeshPro中的TMP_InputField,用来实现输入框的几个小问题
第一,正确设置Scrollbar。 设置Scrollbar之后,不能设置Text Component的Font Size为Auto Size,否则Scrollbar无法正确计算显示。 那么,要想自动适配字体大小,可以让Placeholder中的Font Size设置为Auto,这…...
Docker 介绍 · 安装详细教程
为什么选择 Docker? ✅ 环境一致性 – 告别“在我机器上能跑”的问题,确保开发、测试、生产环境一致。 ✅ 高效轻量 – 秒级启动,资源占用远低于传统虚拟机。 ✅ 跨平台支持 – 可在任何支持 Docker 的环境中运行,包括云服务器、…...
vulnhub:sunset decoy
靶机下载地址https://www.vulnhub.com/entry/sunset-decoy,505/ 渗透过程 简单信息收集 nmap 192.168.56.0/24 -Pn # 确定靶机ip:192.168.56.121 nmap 192.168.56.121 -A -T4 # 得到开放端口22,80 在80端口得到save.zip,需要密码解压。 john破解压缩…...
方案精读:71页制造企业一体化ERP系统项目实施方案【附全文阅读】
今天聊聊制造企业 ERP 系统项目实施方案。 某钾肥企业在发展中面临信息化难题,像物资编码不规范、业务手工化、财务业务脱节等 。为此,打造 “流程驱动,业务整合” 的一体化 ERP 管理平台很关键。它涵盖采购、销售、生产、运营流程,实现供应链、预算、资金、财务整…...
MATLAB遇到内部问题,需要关闭,Crash Decoding : Disabled - No sandbox or build area path
1.故障界面 MATLAB运行时突然中断,停止运行。故障界面如图: MATLAB Log File: C:\Users\wei\AppData\Local\Temp\matlab_crash_dump.21720-1 ------------------------------------------------ MATLAB Log File -----------------------------------…...
【Redis】Redis C++使用
一、Redis的自定义网络协议 1.1 为什么可以编写出一个自定义的Redis客户端 为什么我们可以编写出一个自定义的Redis客户端?因为Redis公开了自己的自定义协议。而对于一些其他软件的客户端,我们无法编写出一个自定义的Redis客户端,因为他们没…...
每日一题(小白)暴力娱乐篇19
样例: 6 1 1 4 5 1 4 输出: 56 66 52 44 54 64 分析题意可以得知,就是接收一串数字,将数字按照下标每次向右移动一位(末尾循环到第一位),每次移动玩计算一下下标和数字的乘积且累加。 ①接收…...
25级总分413数学一142专业124东南大学820考研经验电子信息通信工程,真题,大纲,参考书。
我是南京理工大学的本科生,25 考研一战东大,政治 69,英一 78,数一 142,专业课(820)124,总分 413。我从 3 月正式开始备考,专业课跟着无线电论坛jenny 老师进行学习&#…...
一个基于Django的进销存管理系统Demo实现
第一步:创建 Django 项目 bash 复制 django-admin startproject inventory_system cd inventory_system python manage.py startapp erp 第二步:定义数据模型(models.py) python 复制 from django.db import models from d…...
【数据结构_6上篇】有关链表的oj题
import java.util.*;/* public class ListNode {int val;ListNode next null;ListNode(int val) {this.val val;} }*/ public class Partition {public ListNode partition(ListNode pHead, int x) {// write code here//1.首先要判断链表是否为空的情况if(pHead null){retu…...
【QT】QWidget 概述与核心属性(API)
🌈 个人主页:Zfox_ 🔥 系列专栏:Qt 目录 一:🔥 控件概述 🦋 控件体系的发展阶段 二:🔥 QWidget 核心属性 🦋 核心属性概览🦋 用件可用(…...
微服务篇——SpringCloud
服务注册 Spring Cloud5大组件有哪些? 服务注册和发现是什么意思?Spring Cloud如何实现服务注册发现? nacos与eureka的区别 负载均衡 如何实现负载均衡? Ribbon负载均衡的策略有哪些? 如何自定义负载均衡的策略&…...
如何使用PyCharm自动化测试
如何使用PyCharm自动化测试 1.打开PyCharm右击文件,点击新建项目 按照如图配置,然后点击创建 2.创建好后,点击文件,然后点击设置 按照如图步骤,查看selenium和webdriver-manager是否存在 3.以上都完成后按照如图创…...
记一次某网络安全比赛三阶段webserver应急响应解题过程
0X01 任务说明 0X02 靶机介绍 Webserver(Web服务器)是一种软件或硬件设备,用于接收、处理并响应来自客户端(如浏览器)的HTTP请求,提供网页、图片、视频等静态或动态内容,是互联网基础设施的核心…...
c# 新建不重名的唯一文件夹
在源文件夹内创建唯一目标文件夹 string newFolder GetUniqueFolderName(sourceFolder); Directory.CreateDirectory(newFolder); /// <summary>/// 生成唯一文件夹名称(格式:新建文件夹、新建文件夹1、新建文件夹2...)…...
复现QGIS-MCP教程
由于Claude国内下载不了尝试使用Cursor 下载安装Cursor Cursor - The AI Code Editor 本示例安装的是0.46版本 UV安装 简介 安装 安装成功 配置环境变量 验证 下载代码 git clone gitgithub.com:jjsantos01/qgis_mcp.git QGIS插件安装 文件拷贝 您需要将 qgis_mcp_plu…...
SQL:JOIN 完全指南:从基础到实战应用
JOIN 是 SQL 中最重要也最常用的操作之一,它允许我们从多个表中获取关联数据。本文将全面解析 SQL 中的各种 JOIN 类型,包括 INNER JOIN、LEFT JOIN、RIGHT JOIN、FULL JOIN 以及 CROSS JOIN,并通过实际示例展示它们的应用场景。 一、JOIN 基础概念 1.1 什么是 JOIN JOIN…...
docker部署certimateSSL证书管理自动续签
开源certimate项目地址:https://github.com/usual2970/certimate 官方文档地址:https://docs.certimate.me/docs/introduction 与certbot对比 维度CertbotCertimate安装方式通过包管理器(如apt/yum)安装支持二进制文件、Docker…...
R语言——直方图
参考资料:学习R 如果我们要研究一个连续变量的分布,直方图是最佳的选择。 1、base绘图 在base中可以使用hist函数绘制直方图,与plot函数一样,它没有data参数,须把数据框置于with中。 data(obama_vs_mccain,package&q…...
第4节:Python编程基础 - Python语法快速回顾
1. Python简介与环境配置 Python是一种高级、解释型、通用的编程语言,由Guido van Rossum于1991年首次发布。 它以简洁明了的语法和强大的功能而闻名,广泛应用于Web开发、数据分析、人工智能、科学计算等领域。 1.1 Python的特点 简单易学:…...
十四、C++速通秘籍—函数式编程
目录 上一章节: 一、引言 一、函数式编程基础 三、Lambda 表达式 作用: Lambda 表达式捕获值的方式: 注意: 四、函数对象 函数对象与普通函数对比: 五、函数适配器 1、适配普通函数 2、适配 Lambda 表达式 …...
蓝桥杯 2025 C++组 省 B 题解
可分解的正整数 算法:思维 因为可以有负数 所以除了1以外的任何数都可以构造 当这个数为x构造方法为 -(x-1) -(x-2) -(x-3) ....-1 0 1...x-3 x-2 x-1 x 除了x,x以前的数都会被负数抵消 #include <bits/stdc.h> #define ll long long ll a…...
如何让老电脑运行快些(极限榨干老电脑硬件)
要让老电脑运行更快,可以通过增加虚拟内存、优化系统设置和硬件升级等方法实现。以下是具体建议: 1. 增加虚拟内存(适合硬盘空间大的老电脑) 虚拟内存(页面文件)是硬盘上的一部分空间,用于扩展…...
博物馆小程序怎么做?从0到1打造数字化文化窗口
博物馆小程序怎么做?从0到1打造数字化文化窗口 一、行业痛点:传统博物馆的数字化困局 在数字化浪潮下,传统博物馆普遍面临三大挑战: 客流受限:线下接待能力有限,难以触达更广泛人群 互动单一…...
信息学奥赛一本通 1498:Roadblocks | 洛谷 P2865 [USACO06NOV] Roadblocks G
【题目链接】 ybt 1498:Roadblocks 洛谷 P2865 [USACO06NOV] Roadblocks G 【题目考点】 1. 图论:严格次短路径 严格次短路的路径长度必须大于最短路的路径长度。 非严格次短路的路径长度大于等于最短路的路径长度。 【解题思路】 每个交叉路口是一…...
1.5-APP的架构\微信小程序的架构
1.5-APP的架构\微信小程序的架构 APP的三种开发架构: 原生态APP类型 APP-开发架构-原生态-IDEA 演示:remusic项目源码 NP管理器: http://normalplayer.top/ HttpCanary:https://github.com/mingww64/HttpCanary-SSL-Magisk 安全影…...
【服务器端表单字符验证】
文章目录 一、实验目的二、核心代码实现三、调试关键问题四、总结 一、实验目的 掌握JSP表单验证在服务器端的实现技术,实现对用户输入字符的非空及长度为5的验证,返回对应提示信息并优化用户交互。 二、核心代码实现 前端表单 <form action"…...
