TS学习-2

news/2025/4/1 9:02:11/文章来源:https://www.cnblogs.com/foxt/p/18799315

常用类型和语法

1.any

任意类型,⼀旦将变量类型限制为any,意味着放弃了对该变量的类型检查。

let a:any
//以下赋值无警告
a=100
a='你好'
a=false//隐式any
let b

注意:any类型的变量,可以赋值给任意类型的变量

let c:any
c=9let x:string
x=c //没有报错

2.unknown

未知类型,适用于:起初不确定数据的具体类型,要后期才能确定

  1. unknown可以理解为一个类型安全的any
let a:unknown
//不会报错
a=100
a=false
a='你好'//设置x的数据类型为string
let x:string
x=a//不能将类型'unknown"分配给类型”string“
  1. unknown会强制开发者在使用之前进行类型检查
//第一种
if(typeof a==='string'){x=a
}//第二种: 加断言
x=a as string//第三种
x=<string>a
  1. 读取any类型数据的任何属性都不会报错,unknown相反
let str1:string
str1.toUpperCase()//不报错let str2:any
str2.toUpperCase()//不报错let str3:unknown
str3.toUpperCase()//报错
//强制断言
(str3 as string).toUpperCase()

3.never

never的含义是:任何值都不是,即:不能有值,例如undefinednul
0都不行!

never限制函数返回值的

function demo():never{
}

注意:ts中没有指明任何返回值的函数调用结束也会返回undefined

function throwError(str:string):never{//程序抛出异常,并立刻结束对函数的调用throw new Error('程序异常退出'+str)
}

4.void

void的含义是空,即:函数不返回任何值,调用者也不应依赖其返回值进行任何操作!限制函数返回值的,不能对变量进行限制。

  1. void通常用于函数返回值声明
function logMessage(msg:string):void{console.log(msg)
}
logMessage('你好')

注意:没有编写return指定函数返回值,所以logMessage函数是没有显式
返回值的,但会有一个隐式返回值,是undefined,虽然函数返回类型为void,但也是可以接受undefined的,简单记:undefinedvoid可以接受的一种“空”。

  1. 以下写法符合规范
function logMessage(msg:string):void{console.log(msg)
}function logMessage(msg:string):void{console.log(msg)return;
}function logMessage(msg:string):void{console.log(msg)return undefined
}
  1. 那限制函数返回值时,是不是undefinedvoid就没区别呢?—有区别。因为返回值类型为void的函数,调用者不应依赖其返回值进行任何操作!对比下面两段代码:
function logMessage(msg:string):void{console.log(msg)
}let result = logMessage('你好')if(result){//此行报错:无法测试"void"类型的表达式的真实性console. log('logMessage有返回值')
}
function logMessage(msg:string):undefined{console.log(msg)
}let result = logMessage('你好')if(result){//此行无警告console. log('logMessage有返回值')
}

5.object

实际开发中用的相对较少,因为范围太大了。

object:所有非原始类型,可存储:对象、函数、数组等。

Object:所有可以调用Object方法的类型。除了undefinednull的任何值。

声明对象类型

  1. 限制一般对象可以使用下面形式
//限制person1对象必须有name属性,age为可选属性,可有可无
let personl: { name: string, age?: number }//含义同上,也能用分号做分隔
let person2: { name: string; age?: number }//含义同上,也能用换行做分隔
let person3:{name: stringage?:number
}
//如下赋值均可以
person1={name:'李四',age:18}
person2={name:'张三'}
person3={name:'王五'}
  1. 索引签名:允许定义对象可以具有任意数量的属性,这些属性的键和类型是可变的,常用于:描述类型不确定的属性,(具有动态属性的对象)。
//限制person对象必须有name属性,可选age属性但值必须是数字,同时可以有任意数量、任意类型的其他属性
let person: {name: stringage?:number[key:string]:any//索引签名,完全可以不用key这个单词,换成其他的也可以,保证key的类型是string,其值是any类型//赋值合法
person = {name:'张三',age:18,gender:'男',city:'成都'
}

声明函数类型

//对函数接受的参数进行限制,对函数返回值进行限制
let count: (a: number, b: number) => numbercount = function (x, y) {return x + y
}//箭头函数,js中的写法
count=(x,y)=>{return x+y
}

备注:
TypeScript中的=>在函数类型声明时表示函数类型,描述其参数类型和返回类型。
JavaScript中的=>是一种定义函数的语法,是具体的函数实现。
函数类型声明还可以使用:接口、自定义类型等方式。

声明数组类型

let arr1:string[]
let arr2:Array<string>//泛型arr1=['a','b','c']
arr2=['hello','world']

6.tuple

元组(Tuple)是一种特殊的数组类型,可以存储固定数量的元素,并且每个元素的类型是已知的且可以不同。元组用于精确描述一组值的类型,?表示可选元素。

let arr1:[string,number]
arr1=['hello',1]let arr2:[string,boolean?]
arr2=['hello']let arr3:[number,...string[]]//任意多个string类型
arr3=[100,'a','b']

7.enum

枚举(enum)可以定义一组命名常量,它能增强代码的可读性,也让代码更好维护。

  1. 数字枚举一种最常见的枚举类型,其成员的值会自动递增,且数字枚举还具备反向映射的特点,在下面代码的打印中,不难发现:可以通过值来获取对应的枚举成员名称。
//定义一个描述【上下左右】方向的枚举Direction
enum Direction {Up,Down,Left,Right
}console.log(Direction)//打印Direction会看到如下内容
/*O:'Up',1:'Down',2:'Left',3:'Right',Up:0,Down:1,Left:2,Right:3
*///反向映射
console.log(Direction.Up)
console.log(Direction[0])//此行代码报错,枚举中的属性是只读的
Direction.Up = 'shang'

指定枚举成员的初始值,后面成员从初始值自增

enum Direction {Up = 6,Down,Left,Right
}console.log(Direction.Up); //输出:6
console.log(Direction.Down); // 输出:7
  1. 字符串枚举
enum Direction {Up="up",Down = "down",Left = "left",Right = "right"
}let dir: Direction = Direction.Up;
console.log(dir);// 输出:"up"
  1. 常量枚举

官方描述:常量枚举是一种特殊枚举类型,它使用const关键字定义,在编译时会被内联,避免生成一些额外的代码。

编译时内联:所谓“内联”其实就是TypeScript在编译时,会将枚举成员引用替换为它们的实际值,而不是生成额外的枚举对象。这可以减少生成的JavaScript代码量,并提高运行时性能。

普通枚举:

enum Directions {Up,Down,Left,Right
}let x = Directions.Up;

编译生成js

"use strict";
var Directions;
(function (Directions) {Directions[Directions["Up"] = 0O] = "Up";Directions[Directions["Down"] = 1] = "Down";Directions[Directions["Left"] = 2] = "Left";Directions[Directions["Right"] = 3] = "Right";
})(Directions |I (Directions = {}));let x = Directions.Up;

常量枚举

enum Directions {Up,Down,Left,Right
}let x = Directions.Up;

编译生成js

"use strict";let x = 0 /* Directions.Up */;

8.type

type可以为任意类型创建别名,让代码更简洁、可读性更强,同时能更方便地进行类型复用和扩展。

  1. 基本用法
type num=numberlet price:num
price=100
  1. 联合类型
type Status=number|stringfunction printStatus(data:Status):void{console.log(data)
}printStatus(404)
printStatus('404')type Gender='男'|'女‘
function logGender(str:Gender){console.log(str)
}
logGender('男')
logGender('女')
  1. 交叉类型
//面积
type Area = {height:number;//高width:number;//宽
};//地址
type Address = {num:number;//楼号cell:number; //单元号room:string;//房间号
}//定义类型House,且House是Area和Address组成的交叉类型
type House = Area & Address;//包含Area和Address的所有属性
const house: House = {height:180,width:75,num:6,cell: 3,room:'702'
};

9.特殊情况

  1. 正常情况

在函数定义时,限制函数返回值为void,那么函数的返回值就必须是空。

function demo():void{//返回undefined合法return undefined//以下返回均不合法return 100return falsereturn nullreturn []
}
demo()
  1. 特殊情况
//自定义一个LogFunc类型,它的类型是函数,返回值为void
type LogFunc = () => void//报错,此时LogFunc为类型,类似于number=9
LogFunc=function(){
}const f1: LogFunc = () => {return 100;//允许返回非空值
}const f2:LogFunc= ()=>200; // 允许返回非空值const f3: LogFunc = function(){return 300;//允许返回非空值
}

10.类相关知识

class Person {//属性声明name: stringage: number//构造器,必须写类型constructor(name: string, age: number){this.name = namethis.age = age}//方法speak() {console.log('我叫:${this.name},今年${this.age}岁')}
}//Person实例
const p1=new Person('周杰伦',38)//继承
class Student extends Person{grade:stringconstructor(name:string,age:number,grade:string){super(name,age)this.grade=grade}study(){console.log('${this.name}正在学习中。。。。。')}//重写父类方法   1.与父类相同的名字  2.在函数前加overrideoverride speak(){console.log('我是学生,我叫:${this.name},今年${this.age}岁')}
}const s1=new Student('许同学',16,'一年级')
s1.study()

11.属性修饰符

5

属性简写形式

简写前

class Person {public name: string;public age: number;constructor(name: string, age: number){this.name = name;this.age = age;}
}

简写后

class Person {constructor(public name: string,public age: number){}
}

12.抽象类

抽象类是一种无法被实例化的类,专门用来定义类的结构和行为,类中可以写抽象方法,也可以写具体实现。抽象类主要用来为其派生类提供一个基础结构,要求其派生类必须实现其中所有的抽象方法。抽象类不能实例化,其意义是可以被继承,抽象类里可以有普通方法、也可以有抽象方法

abstract class Package {constructor(public weight: number){}//抽象方法:用来计算运费,不同类型包裹有不同的计算方式abstract calculate(): number//abstract calculate(x:string,y:string): number//具体方法:打印包裹详情printPackage(){console.log('包裹重量为:${this.weight}kg,运费为:${this.calculate()}元');}
}//标准包裹
class StandardPackage extends Package{constructor(weight:number,public unitPrice:number //每公斤的固定费率,简写形式){super(weight)}//实现抽象方法:计算运费calculate(): number {return this.weight * this.unitPrice;}
}//创建标准包裹实例
const s1 = new StandardPackage(10,5)
s1.printPackage()//特快包裹
class ExpressPackage extends Package {constructor(weight:number,private unitPrice:number,//每公斤的固定费率(快速包裹更高)private additional:number // 超出1okg以后的附加费){ super(weight)}//实现抽象方法:计算运费calculate(): number {if(this.weight > 10){//超出10kg的部分,每公斤多收additional对应的价格return 10 * this.unitPrice + (this.weight - 10) * this.additional}else {return this.weight * this.unitPrice;}}}//创建特快包裹实例
const e1 = new ExpressPackage(13,8,2)
el.printPackage()

总结:何时使用抽象类?

  • 定义通用接口:为一组相关的类定义通用的行为(方法或属性)时。
  • 提供基础实现:在抽象类中提供某些方法或为其提供基础实现,这样派生类就可以继承这些实现。
  • 确保关键实现:强制派生类实现一些关键行为。
  • 共享代码和逻辑:当多个类需要共享部分代码时,抽象类可以避免代码重复。

13.interface(接口)

interface是一种定义结构的方式,主要作用是为:类、对象、函数等规定一种契约,这样可以确保代码的一致性和类型安全,但要注意interface只能定义格式,不能包含任何实现!

  1. 定义类结构
//定义接口
interface PersonInterface {name: stringage:numberspeak(n: number): void
}//定义一个类 Person,实现PersonInterface接口
class Person implements PersonInterface {constructor(public name: string,public age: number){}//实现接口中的speak方法speak(n: number): void {for (let i = 0; i< n; i++) {//打印出包含名字和年龄的问候语句console.log('你好,我叫${this.name},我的年龄是${this.age}');}}
}//创建一个Person类的实例p1,传入名字'tom'和年龄18
const p1 = new Person('tom', 18);
pl.speak(3)
  1. 定义对象结构
interface UserInterface {name:stringreadonly gender:string //只读属性age?:number// 可选属性run: (n: number) => void
}const user: UserInterface = {name:"张三",gender:'男',age:18,run(n) {console.log('奔跑了${n}米')
}
  1. 定义函数结构
interface CountInterface {(a: number,b: number):number;
}
const count: CountInterface = (x, y) => {return x + y
}
  1. 接口之间的继承
interface PersonInterface {name:string //姓名age:number // 年龄
}//继承的接口
interface StudentInterface extends PersonInterface {grade:string //年级
}const stu: StudentInterface = {name:'张三',age:25,grade:'高三'
}
  1. 接口的自动合并
// PersonInterface接口
interface PersonInterface {//属性声明name: stringage:number
}//给PersonInterface接口添加新属性
interface PersonInterface {//方法声明speak(): void
}// Person类实现PersonInterface
class Person implements PersonInterface {name:stringage:number//构造器constructor(name: string, age: number) {this.name = namethis.age = age}//方法speak() {console.log('你好!我是老师:',this.name)}
}

总结:何时使用接口?

  • 定义对象的格式:描述数据模型、AP响应格式、配置对象....等等,是开发中用的最至的场景。
  • 类的契约:规定一个类需要实现哪些属性和方法。
  • 扩展已有接口:一般用于扩展第三方库的类型,这种特性在大型项目中可能会用到。

一些相似的概念的区别

1.interface与type

相同点

interface和type都可以用于定义对象结构,在定义对象结构时两者可以互换。

//使用 interface 定义 Person 对象
interface PersonInterface {name:string;age:number;speak(): void;
}// 使用type 定义 Person 对象
type PersonType ={name: string;age:number;speak(): void;
}
// 使用PersonInterface
let person: PersonInterface ={name:'张三’,age:18,speak(){console.log('我叫:${this.name},年龄:${this.age}')}
}//使用PersonType
let person: PersonType = {name:'张三',age:18,speak(){console.log('我叫:${this.name},年龄:${this.age}')}
}

不同点

interface:更专注于定义对象和类的结构,支持继承、合并。
type:可以定义类型别名、联合类型、交叉类型,但不支持继承和自动合并。

接口的继承与合并

interface PersonInterface {name:string //姓名age:number//年龄
}//利用接口的自动合并
interface PersonInterface {speak:()=>void
}
//利用接口之间的继承
interface StudentInterface extends PersonInterface {grade:string //年级
}const student: StudentInterface = {name:'李四',age:18,grade:'高二'speak() {console.log(this.name,this.age,this.grade)}
}

type的交叉类型

//使用type定义Person类型,并通过交叉类型实现属性的合并
type PersonType = {name:string;//姓名age:number;//年龄
}&{speak: () => void;
};//使用type定义Student类型,并通过交叉类型继承PersonType
type StudentType = PersonType &{grade:string;//年级
}const student: StudentType = {name:'李四',age:18,grade:'高二',speak() {console.log(this.name, this.age, this.grade);
};

2.interface与抽象类

相同点:都能定义一个类的格式(定义类应遵循的契约)
不相同:接口:只能描述结构,不能有任何实现代码,一个类可以实现多个接口。
抽象类:既可以包含抽象方法,也可以包含具体方法,一个类只能继承一个抽象类。

泛型

泛型允许我们在定义函数、类或接口时,使用类型参数来表示未指定的类型,这些参数在具体
使用时,才被指定具体的类型
,泛型能让同一段代码适用于多种类型,同时仍然保持类型的安
全性。

如下代码中 就是泛型,(不⼀定⾮叫 T ),设置泛型后即可在函数中使⽤ T 来表示

  1. 泛型函数
function logData<T>(data: T): T{console.log(data)return data
}logData<number>(100)
logData<string>('hello')
  1. 多个泛型
function logData<T, U>(datal: T, data2: U): T | U{console.log(datal,data2)return Date.now()%2? datal : data2
}logData<number, string>(100, 'hello')
logData<string, boolean>('ok', false)
  1. 泛型接口
interface PersonInterface<T> {name:string,age:number,extraInfo: T//额外信息
}let pl: PersonInterface<string>
let p2: PersonInterface<number>pl={name:'张三',age:18,extraInfo:'一个好人'}
p2={ name:'李四',age:18,extraInfo:250}
  1. 泛型类
class Person<T> {constructor(public name: string,public age: number,public extraInfo:T){}speak(){console.log('我叫${this.name}今年${this.age}岁了')console.log(this.extraInfo)}
}
const p1 = new Person<number>("tom", 30, 250);

类型声明文件

类型声明文件是TypeScript中的一种特殊文件,通常以·d.ts作为扩展名。它的主要作用是为现有的JavaScript代码提供类型信息,使得TypeScript能够在使用这些JavaScript库或模块时进行类型检查和提示。

export function add(a, b) {return a + b;
}export function mul(a, b) {return a * b;
}
declare function add(a: number, b: number): number;
declare function mul(a: number, b: number): number;
export { add, mul };
// example.ts
import { add, mul } from "./demo.js";
const x = add(2, 3); // x 类型为 number
consty = mul(4, 5); // y 类型为 number
console.log(x,y)

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

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

相关文章

使用AOP技术实现接口验签

一、背景 在给第三方提供接口时,我们需要对接口进行验签。具体来说,当外部系统调用我们的接口时,请求中需要携带一个签名,我们接收到请求后,会解析数据并校验签名是否正确,以确保请求的合法性和安全性。为了在不同项目中方便地使用这一功能,我们将签名校验规则封装成一个…

UE5--004--Procedural Generation

1. BP_ProceduralMeshes蓝图2. BP_SplinePlacement蓝图2.1 ConstructionScript2.2 CalculateNumberOfInstances2.3 Spline3. Level

20242402 2024-2025-2《Python程序设计》实验二报告

20242402 2024-2025-2 《Python程序设计》实验二报告 课程:《Python程序设计》 班级: 2424 姓名: 张宇涵 学号:20242402 实验教师:王志强 实验日期:2024年3月27日 必修/选修: 公选课 1.实验内容设计并完成一个计算器程序,完成加减乘除模等运算,功能多多益善。考核基本…

【医疗行业】健康医疗数据合规流通系列之一:概念辨析与监管框架

一、健康医疗数据的定义及分类分级 1.1 健康医疗数据的定义 健康医疗数据在法律上的概念并不明晰。理论界与实务界对健康医疗数据的认识差异首先是在称谓上,如“健康数据”、“健康医疗数据”、“医疗数据”等。立法概念不明晰和称谓争议背后的实质,反映的是健康医疗数据产业…

day:33 jmeter性能测试——获取接口

获取接口的三种方式: 第一种:抓包:写入接口fiddler或f12第二种方式 :录制脚本工具badboy 录制 1、点击安装包2、快捷方式到桌面3、点击打开badoy4、导出接口5、将录制的接口导入到jmeter种第三种方式:jmeter中有反向代理录制脚本 1.工作中添加http代理服务器2.编辑代理服务…

C#程序安装包制作流程

1.莫高设计软件-网页版 设计icon 2.icon.png 转化成 icon.ico格式 转化网址:favicon制作 - 在线工具3.拓展 - 拓展管理中下载 VS官方的安装包制作工具4.解决方案 - 新建项目 - 新建setup - project 项目(即安装包制作项目) 5. 6.7.

基于Verilog的7段数码管动态扫描驱动模块设计

1、7段数码管动态扫描驱动模块概述 功能:通过动态扫描方式驱动6位共阳极7段数码管 特性: (1)支持6位数码管显示(24位输入数据,每4位代表一个数字) (2)采用动态扫描技术,降低功耗 (3)支持十六进制显示(0-F) (4)带异步复位功能 2、7段数码管模块硬件原理图+6位一…

leetcode每日一题:图中的最长环

题目 2360. 图中的最长环 给你一个 n 个节点的 有向图 ,节点编号为 0 到 n - 1 ,其中每个节点 至多 有一条出边。 图用一个大小为 n 下标从 0 开始的数组 edges 表示,节点 i 到节点 edges[i] 之间有一条有向边。如果节点 i 没有出边,那么 edges[i] == -1 。 请你返回图中的…

三菱PLC数据 转 EthernetIP项目案例

VFBOX协议转换网关支持PLC,modbus,EthernetIP,Profinet,CCLink,EtherCAT,IEC61850,IEC104,bacnet,DLT645,HJ212,opc ua,opc da,DNP3。目录 1 案例说明 1 2 VFBOX网关工作原理 1 3 准备工作 2 4 网关采集三菱PLC数据 2 5 使用ETHERNETIP转发数据 5 6 其他说明 7 7 …

比较LLM的function calling,Agent 和MCP

比较对比维度 ​MCP(Model Context Protocol)​ ​Function Calling ​Agent(智能体)​​定义 由 Anthropic 推出的开放协议,标准化 LLM 与外部数据源、工具的通信接口。 LLM 调用外部函数的机制,通过 JSON 参数规范模型与外部系统的交互。 自主运行的智能系统,通过分析…

20C++数组(1)——教学

1、什么是数组; 2、数组越界; 3、循环移位; 4、冒泡排序一、什么是数组 教学参考视频尼克、格莱尔等5位同学进行了一次信息学测试,试编一程序,实现查分功能。先输入成绩,然后输入学号输出相应的成绩。按以前方法:可以用al~a5分别保存1~5号同学的成绩,然后进行判断,若输入…

102201542曾庆徽-综测成绩证明材料

2023-2024年度下学期2024-2025年度上学期