彻底理解TypeScript对象语法

目录

  • 对象
    • 类型表示
    • 索引签名
    • 定义
    • 使用
    • 继承
    • 成员修饰符
    • 参数属性
    • getters / setters
    • 类的类型
    • 抽象类 `abstract`
    • 类实现接口
    • 抽象类和接口区别

对象

TypeScript允许为对象的每个属性指定类型,并可以结合接口、类型别名等工具来定义复杂的对象结构

类型表示

/* 基本表示 */
let obj1: { name: string, age: number } = {name: 'obj1',age: 8
}
console.log(obj1) // {name: 'obj1', age: 8}/* 可选只读 */
let obj2: {readonly name: string, age?: number} = {name: 'obj2'
}
// obj2.name = 'obj' // 无法为“name”赋值,因为它是只读属性
console.log(obj2.name, obj2) // obj2 {name: 'obj2'}/* 嵌套 */
let obj3: {name: string, age: number, address: { city: string; zipCode?: number }} = {name: 'obj3',age: 18,address: {city: '北京'}
}
console.log(obj3) // {name: 'obj3', age: 18, address: {city: '北京'}}/* 接口定义 interface */
interface IObj4 {readonly name: string,age: numberaddress: { city: string; zipCode?: number }
}
let obj4: IObj4 = {name: 'obj4',age: 28,address: {city: '北京'}
}
console.log(obj4) // {name: 'obj4', age: 28, address: {city: '北京'}}/* 类型别名定义 type */
interface obj5Type {readonly name: string,age: numberaddress: { city: string; zipCode?: number }
}
let obj5: obj5Type = {name: 'obj5',age: 38,address: {city: '深圳'}
}
console.log(obj5) // name: 'obj5', age: 38, address: {city: '深圳'}}

索引签名

用于描述对象属性的键和值不确定的情况,可以定义对象允许的键和值类型,适用于键值对数量和名称不固定的对象

  • 键类型只能是 stringnumbersymbol 或模板字符串值的类型可以是任意指定的类型

    interface IInfo1 {[index: number]: number
    }
    const indexArr: IInfo1 = [123, 321] // 要满足可以通过number索引取到number,对象不满足
    console.log(indexArr)interface IInfo2 {[key: string]: string
    }
    const keyObj: IInfo2 = {name: 'keyObj'
    }
    console.log(keyObj) // 要满足可以通过string索引拿到的值也是stringconst mySymbol = Symbol('mySymbol');
    interface IInfo3 {[fn: symbol]: () => void
    }
    const symObj: IInfo3 = {[mySymbol]: function (){}
    };
    console.log(symObj[mySymbol]); // 输出: 函数type templateType = `prefix_${string}`; // 必须拼接变量,只写字符串会报错
    interface IInfo4 {[template: templateType]: number;
    }
    const templateObj: IInfo4 = {'prefix_name': 42,
    };
    console.log(templateObj['prefix_name']);  // 输出: 42
    
  • 索引可以同时存在多个,但数字索引的值类型必须是字符索引(包含模板字符串)值类型的子类型

    interface IInfo5 {[index: number]: number/* 下面注释的一行代码会报错: “number”索引类型“number”不能分配给“string”索引类型“string”因为:所有的数字类型都是会转成字符串类型去对象中获取内容当是一个数字的时候,既要满足通过number去拿到的内容, 又不会和string拿到的结果矛盾比如当我们使用number索引签名取值时,比如obj[1]取到的是number,相当于obj['1']取到的也应该是number但使用string索引签名取值时,比如obj['age']取到的是string,但obj['age']取到的值可能和obj[1]取到的是同一个值,他怎么可能是数字又是string,所以报错*/// [key: string]: string [key: string]: number[fn: symbol]: () => void[template: templateType]: number;
    }
    const mulObj: IInfo5 = {age: 123,[mySymbol]: function (){},'prefix_name': 42
    }
    
  • 可以在包含索引签名的接口中定义具体的属性,但这些属性的值类型必须与索引签名的值类型一致或兼容

    interface IInfo6 {[index: number]: number[key: string]: number[fn: symbol]: () => void[template: templateType]: number;// checked: boolean // 报错// str: string // 报错sum: number
    }
    const mulAttrObj: IInfo6 = {sum: 20 // 必须要有此属性
    }
    

在早期的JavaScript开发中(ES5)我们需要通过函数和原型链来实现类和继承,从ES6开始,引入了class关键字,可以更加方便的定义和使用类。TypeScript作为JavaScript的超集,也是支持使用class关键字的,并且还可以对类的属性和方法等进行静态类型检测

定义

使用class关键字来定义一个类,可以声明类的属性,在类的内部声明类的属性以及对应的类型,基本和JavaScript是一样的

  • 如果类型没有声明默认是any,可以给属性设置初始化值

  • 在默认的 strictPropertyInitialization模式下面我们的属性是必须初始化的,没有初始化编译就会报错

  • 如果在strictPropertyInitialization模式下不希望给属性初始化,可以使用 name!: string 语法

  • 类有自己的构造函数constructor,通过new关键字创建 实例时,构造函数会被调用

  • 构造函数不需要返回任何值,默认返回当前创建出来的实例

  • 类中可以有自己的函数,定义的函数称之为方法

使用

class Person {name: string;age: number;constructor(name: string, age: number) {this.name = name;this.age = age;}greet(): void {console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);}
}const person = new Person("John", 30);
person.greet();  // 输出:Hello, my name is John and I am 30 years old.

继承

class Person {name: string;age: number;constructor(name: string, age: number) {this.name = name;this.age = age;}greet(): void {console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);}
}class Employee extends Person {jobTitle: string;constructor(name: string, age: number, jobTitle: string) {super(name, age);  // 调用父类的构造函数this.jobTitle = jobTitle;}describe(): void {console.log(`${this.name} works as a ${this.jobTitle}`);}
}const employee = new Employee("Jane", 25, "Software Developer");
employee.greet();      // 输出:Hello, my name is Jane and I am 25 years old.
employee.describe();   // 输出:Jane works as a Software Developer.

成员修饰符

TypeScript中,类的属性和方法支持三种修饰符:public、private、protected

  • public 修饰的是在任何地方可见、公有的属性或方法,默认编写的属性就是public

  • private 修饰的是仅在同一类中可见、私有的属性或方法

  • protected 修饰的是仅在类自身及子类中可见、受保护的属性或方法

class Shape {public width: numberprivate _height: number // 私有通常使用_表示constructor (width: number, height: number){this.width = widththis._height = height}protected getArea(): number {return this.width * this._height}
}
let s = new Shape(10, 20)
console.log(s.width)
console.log(s._height) // 属性“_height”为私有属性,只能在类“Shape”中访问
console.log(s.getArea()) // 属性“getArea”受保护,只能在类“Shape”及其子类中访问class circle extends Shape {r: numberconstructor(width: number, height: number, r: number) {super(width, height)this.r = r}getWhr(){return this.getArea() * this.r // getArea()可在子类中访问}
}

参数属性

  • 可以把一个构造函数参数转成一个同名同值的类属性,这些就被称为参数属性(parameter properties
  • 可以通过在构造函数参数前添加一个可见性修饰符 public private protected 或者 readonly 来创建参数属性,最后这些类属性字段也会得到这些修饰符
class Shape {constructor (public width: number, private height: number){this.width = widththis.height = height}protected getArea(): number {return this.width * this.height}
}
let s = new Shape(10, 20)
console.log(s.width)
console.log(s.height) // 属性“height”为私有属性,只能在类“Shape”中访问
console.log(s.getArea()) // 属性“getArea”受保护,只能在类“Shape”及其子类中访问class circle extends Shape {constructor(width: number, height: number, readonly r: number) {super(width, height)this.r = r}getWhr(){return this.getArea() * this.r // getArea()可在子类中访问}
}

getters / setters

TypeScript 支持使用 getset 关键字来定义属性的访问器(getter)和设置器(setter),当有一些私有属性是不能直接访问的,或者某些属性想要监听它的获取(getter)和设置(setter)的过程,这个时候可以使用存取器

class Person {private _age: number;constructor(age: number) {this._age = age;}get age(): number {return this._age; }set age(value: number) {if (value > 0) {this._age = value;}}
}const person = new Person(30);
console.log(person.age);  // 输出:30  这时可以通过age拿到私有属性_age
person.age = 35;
console.log(person.age);  // 输出:35

类的类型

抽象类 abstract

允许你定义一些具有共同功能的类,但不能直接实例化。抽象类通常用于定义共享的结构和行为,而具体的实现则交由继承它的子类来完成

  • 抽象方法必须存在于抽象类中,抽象类是使用abstract声明的类

  • 抽象类是不能被实例化(也就是不能通过new创建)

  • 抽象类可以包含抽象方法,也可以包含属性、方法和构造函数

  • 有抽象方法的类,必须是一个抽象类

  • 抽象方法必须被子类实现,否则该类必须是一个抽象类

abstract class Shape {// 抽象方法,没有方法体,必须在子类中实现,每个形状可以实现自己的获取面积方法abstract getArea(): numberconstructor(public w: number, public h: number) {this.w = wthis.h = h}// 具体方法,子类可以直接继承使用divide(): void {console.log("divide...");}
}class Circle extends Shape {constructor(w: number, h: number, private r: number){super(w, h)this.r = r}getArea(): number { // 必须实现this.divide() // divide...return this.w * this.h * this.r}
} 
const s = new Shape(10, 20) // 报错:无法创建抽象类的实例
const c = new Circle(10, 20, 30)
console.log(c.getArea()) // 6000

类实现接口

  • 通过接口(interface),你可以定义对象应该具有哪些属性和方法,然后通过实现接口的类来确保这些类具有所需的行为和结构

  • 使用 implements 关键字,类可以实现接口。实现接口的类必须提供接口中定义的所有属性和方法的具体实现

  • 如果被一个类实现,那么在之后需要传入接口的地方,都可以将这个类传入

interface IJump {jump: () => void
}
interface IEat {eat: () => void
}class Action implements IJump, IEat {constructor(public name: string, public age: number) {this.name = namethis.age = age}jump() {console.log(`${this.name}爱jump`)}eat() {console.log(`${this.name}爱eat`)}
}
const a = new Action('action', 18)
a.jump() // action爱jump
a.eat() // action爱eat

抽象类和接口区别

抽象类在很大程度上和接口会有点类似:都可以在其中定义一个方法,让子类或实现类来实现对应的方法,但他们还是有区别的:

  • 接口(interface) 只定义结构,不包含任何实现细节,所有的实现都必须由类来完成

  • 抽象类可以定义部分实现,并且允许子类继承这些实现

  • 接口 只可以定义抽象的方法和属性,而 抽象类 可以包含具体的方法和属性

  • 一个类可以实现多个接口,但只能继承一个抽象类

  • 抽象类是对事物的抽象,表达的是 is a 的关系。猫是一种动物(动物就可以定义成一个抽象类)

  • 接口是对行为的抽象,表达的是 has a 的关系。猫拥有跑(可以定义一个单独的接口)、爬树(可以定义一个单独的接口) 的行为

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

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

相关文章

MyBatis 用法详解

文章目录 一、普通 SQL1.1 注解实现:1.1.1 参数传递:1.1.2 增(Insert):1.1.3 删(Delete):1.1.4 改(Update):1.1.5 查(Select&#xff…

贴吧软件怎么切换ip

在网络使用中,有时我们需要切换IP地址来满足特定的需求,比如需要切换贴吧软件IP以进行不同的操作。本文将介绍几种贴吧切换IP地址的方法,帮助用户更好地管理自己的网络身份和访问权限。 1、更换网络环境‌ 通过连接到不同的Wi-Fi网络或使用移…

微服务之间的相互调用的几种常见实现方式对比

目录 微服务之间的相互调用的几种实现方式 一、HTTP HTTP/RESTful API调用工作原理 二、RPC 设计理念与实现方式 协议与传输层 RPC远程调用工作原理 应用场景与性能考量 特点 三、Feign 设计理念与实现方式 协议与传输层 Feign调用的基本流程 Feign调用的工作原理…

钢铁行业3大改造方向 智能仪器亦起到重要作用!

钢铁企业新的改造方向主要包括超低排放改造、能效改造和数字化转型。‌这些政策旨在提升钢铁行业的环保水平、能效和智能化水平。其中智能仪器的加入,为钢铁企业数字化智能化自动化改造带来新的活力。 具体来说,到2027年,钢铁行业将实现以下目…

ubuntu-24.04.1 系统安装

使用VMware虚拟机上进行实现 官网下载地址: https://cn.ubuntu.com/download https://releases.ubuntu.com 操作系统手册: https://ubuntu.com/server/docs/ (里面包含安装文档) 安装指南(详细)&#xff1a…

华为云应用侧Android Studio开发

本文将介绍如何使用AndroidStudio开发APP完成与接入华为云IoTDA设备的对接,包括属性参数获以及取命令下发。 一、鉴权认证 应用侧需要通过IAM服务鉴权,获取token,华为账号创建 IAM 用户, 可以为创建的用户分配权限 认证鉴权_设…

PHP智慧餐饮新风尚点餐系统

智慧餐饮新风尚点餐系统 —— 美食与科技的完美碰撞 🍽️ 开篇:智慧餐饮的崛起 在快节奏的现代生活中,智慧餐饮正逐渐成为我们日常的一部分。随着科技的飞速发展,餐饮行业也在不断创新,力求为顾客提供更加便捷、高效…

深信服上网行为管理AC无法注销在线用户

下图用户认证成功后无法注销 很多入网的用户都是使用的这个账号 针对单个IP强制注销也不生效 解决步骤: 接入管理-用户管理-用户绑定管理-用户绑定 删除绑定免认证的配置 删除后所有用户会强制注销掉,重新登录即可 可添加主页联系方式帮忙远程解决问…

codeforces- 973-div2----补题

1、求最小时间 思路&#xff1a;简单的模拟 木桶效应 #include<iostream> #include<algorithm> using namespace std; typedef long long ll; int dx[] { 0,1,0,-1 }; int dy[] { 1,0,-1,0 }; const ll N 2e5 5; const ll mod 1e9 7; ll a[N]; void solve…

免费又好用的保护网站WAF,基于语义引擎的waf雷池社区版推荐

为什么传统规则防护失效了&#xff1f;&#x1f914; 目前&#xff0c;大多数 Web 应用防火墙&#xff08;WAF&#xff09;依赖规则匹配来识别和阻断攻击流量。然而&#xff0c;随着 Web 攻击的低成本、复杂多样的手段和频繁爆发的高危漏洞&#xff0c;管理人员不得不频繁调整防…

pyQT5+vscode python开发环境搭建

1、下载安装python https://www.python.org/ftp/python/3.9.13/python-3.9.13-amd64.exe 注意&#xff1a;高版本python的pyQT5可能有兼容性问题,我之前装的python3.11时pyuic就不工作&#xff0c;就降级为3.9 2、安装pip 及 pyQT python -m ensurepip --default-pip pip i…

蓝桥杯【物联网】零基础到国奖之路:十六. 扩展模块之矩阵按键

蓝桥杯【物联网】零基础到国奖之路:十六. 扩展模块之矩阵按键 第一节 硬件解读第二节 CubeMX配置第三节 MDK代码 第一节 硬件解读 扩展模块和ADC模块是一摸一样的&#xff0c;插在主板上。 引脚对应关系&#xff1a; PB6-ROW1 PB7-ROW2 PB1-COLUMN1 PB0-COLUMN2 PA8-COLUMN3 …

骨传导耳机哪个牌子好?2024年度五大高分骨传导机型推荐!

骨传导耳机哪个牌子好&#xff1f;作为专业健身教练&#xff0c;我平日在训练的时候会使用骨传导耳机来听歌&#xff0c;不过&#xff0c;随着骨传导耳机热度逐渐提高&#xff0c;如今市场上骨传导耳机品牌繁多&#xff0c;类型各异&#xff0c;它们的质量差距也很大。很多网红…

【Java】多线程代码案例

多线程代码案例 单例模式初步了解饿汉模式懒汉模式线程安全问题分析存在的问题 生产者消费者模型初识生产者消费者模型初识阻塞队列生产者消费者模型的意义BlockingQueue阻塞队列模拟实现 定时器初识计时器初识Timer类初识 schedule() 方法简易定时器的实现思路讲解代码书写 线…

耳机座接口会被TYPE-C取代吗?

耳机座接口&#xff0c;即传统的3.5mm耳机插孔&#xff0c;一直以来都是音频设备的标准配置。然而&#xff0c;随着科技的发展和用户需求的变化&#xff0c;TYPE-C接口逐渐崭露头角&#xff0c;成为许多设备的主流选择。这一趋势引发了一个重要问题&#xff1a;耳机座接口会被T…

Collection 集合框架

Collection 集合框架 各类集合 Set TreeSet 基于红黑树实现&#xff0c;支持有序性操作&#xff0c;例如根据一个范围查找元素的操作。但是查找效率不如 HashSet&#xff0c;HashSet 查找的时间复杂度为 O(1)&#xff0c;TreeSet 则为 O(logN)。 HashSet 基于哈希表实现&…

php常用的注释符号

如果没有安装vscode和小皮&#xff0c;请点击下方链接安装&#xff1a; Vscode、小皮面板安装-CSDN博客 在学习php过程中&#xff0c;肯定少不了注释&#xff0c;也可以理解为备注的信息&#xff0c;来提醒自己这段代码有什么用&#xff0c;是什么意思等&#xff0c;接下来就介…

【Redis】网络模型(day10)

在本篇文章中&#xff0c;主要是对五种网络模型进行一个简单的介绍&#xff0c;然后对Redis4.0和6.0的网络模型进行一个概述。 用户空间和内核空间 在Linux系统上&#xff0c;分为用户空间、内核空间和硬件设备。硬件设备主要包括CPU、内存、网卡等物体&#xff0c;内核应用去…

QT开发--QT基础

第0章 QT工具介绍 0.1 编译工具 uic&#xff0c;rcc&#xff0c;moc&#xff0c;qmake 都是 qt 的工具 uic 主要是 编译 .ui文件 -> ui_xxx.h //.ui文件 .h rcc 主要是 编译 资源文件.qrc文件 -> xxx.rcc …

SpringBoot3.3 优雅启停定时任务

定时任务是非常常见的功能,在一个复杂的应用程序中,如何优雅地管理这些定时任务的启动与停止尤为重要。 Spring Boot 提供了强大的任务调度支持,通过@Scheduled注解可以轻松地创建定时任务,并且可以通过配置来灵活地管理这些任务的执行环境。在本文中,我们将深入探讨如何…