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

4. TypeScript 类型推断与类型组合

一、类型推断

(一) 什么是类型推断

TypeScript 的类型推断会根据变量、函数返回值、对象和数组的赋值和使用方式,自动确定它们的类型。

  • 这一特性减少了显式类型注解的需要,在保持类型安全的同时简化了代码。
  • 通过分析上下文和初始值,TypeScript 能确保变量和函数在整个代码中以一致且预期的类型进行操作。
let age = 25;
let name = "John";console.log(`Age: ${age}`);
console.log(`Name: ${name}`);

在这个示例中,

  • TypeScript 根据赋值自动推断 age 为数字类型,name 为字符串类型。
  • 这种自动检测机制在无需显式类型注解的情况下,确保了类型安全。

(二) 变量类型的推断

let x = 10; // TypeScript 推断 x 为 number 类型
console.log(typeof x);

在这个示例中,

  • TypeScript 根据初始值 10 推断变量 x 的类型为 number。
  • 这确保了 x 只能保存数值类型的值,从而提高了类型安全性。

输出:

number

(三) 数组类型推断

let fruits = ["Apple", "Banana", "Cherry"]; // TypeScript 推断 fruits 为 string[]
console.log(fruits);

在这个例子中,

  • TypeScript 根据初始值推断出 fruits 的类型为字符串数组(string[])。
  • 这可以防止添加其他类型的元素,保持数组的一致性。

输出:

[ 'Apple', 'Banana', 'Cherry' ]

(四) 函数返回类型的推断

function add(a: number, b: number) {return a + b; // TypeScript 推断返回类型为 number
}
console.log(add(5, 10));

在这个例子中,

  • add 函数的返回类型被推断为 number,因为它返回两个数字的和。
  • 这确保了该函数始终返回数值类型,避免了类型相关的错误。

输出:

15

二、类型组合

在 TypeScript 中,类型组合使你能够通过将多种类型合并为单一类型,创建灵活且可复用的组件。这种方式可以更精确地控制数据的结构,特别适用于处理复杂的数据结构或在类型安全的前提下处理不同的情况。

(一) 联合类型

TypeScript 联合类型 具有将一种或多种不同类型的数据(例如 numberstringfloatdouble 等)组合在一起的能力。它是表达变量可以拥有多种类型的最强大方式。使用 管道符号('|') 来组合两个或多个数据类型,从而实现联合类型。语法如下:

(type1|type2|type3|...|type-n)

1. 一般用法

例1:

let value: number | string;  
value = 190;  
console.log("Numeric value of the value: " + value);  
value = "Welcome to TypeScript!";  
console.log("String value of the value: " + value);

将上述代码编译后,会生成以下的 JavaScript 代码。

"use strict";
let value;
value = 190;
console.log("Numeric value of the value: " + value);
value = "Welcome to TypeScript!";
console.log("String value of the value: " + value);

输出:

190
Welcome to TypeScript!

例2:

在这个例子中,变量 geeks 是联合类型,用 (string | number) 表示。因此,我们可以给它赋值为字符串或数字,除此之外的类型都不允许。

let geeks: (string | number);
geeks = 123;   // 可以,赋值为数字
geeks = "XYZ"; // 可以,赋值为字符串
geeks = true;  // 编译错误,不允许赋值为布尔类型

2. 函数参数作为联合类型

我们可以将联合类型用作函数参数。在这个例子中,参数 geeks 是联合类型,你可以传入字符串或者数字类型的值,否则编译器会报错。示例如下:

function displayType(geeks: (string | number)) {if(typeof(geeks) === "number")console.log('geeks 是数字。')else if(typeof(geeks) === "string")console.log('geeks 是字符串。')
}// 输出:geeks 是数字。
displayType(49); // 输出:geeks 是字符串。
displayType("GFG"); // 编译错误:类型 'true' 的参数不能赋给类型为 string | number 的参数
displayType(true);  

3. 数组作为联合类型

在联合类型中,我们也可以传递数组。程序声明了一个数组,该数组可以表示数字集合或字符串集合。示例:

// 由 TypeScript 1.8.10 生成
var arr = [2, 5, 7, 5, 11, 15];console.log("Display the array elements");// 循环输出数组元素
for (var i = 0; i < arr.length; i++) {console.log(arr[i]);
}// 重新赋值为字符串数组
arr = ["A", "G4G", "GFG", "GeeksforGeeks"];console.log("Display the array elements");// 循环输出数组元素
for (var i = 0; i < arr.length; i++) {console.log(arr[i]);
}

输出:

Display the array elements
2
5
7
5
11
15
Display the array elements
Geeks
G4G
GFG
GeeksforGeeks

联合类型可以替代枚举(enums):枚举是一组常量类型的列表,默认情况下,枚举的索引值是(0、1、2、3 等)。枚举实际上是被编译转换的(将一种语言编写的源代码转换成另一种具有相似抽象级别的语言),最终生成类似 JavaScript 的代码。

(二) 类型别名

在 TypeScript 中,类型别名允许你为已存在的类型指定一个自定义名称,从而提升代码的可读性和复用性。

  • 为复杂类型(如联合类型或对象类型)提供简写形式。
  • 允许为基本类型、对象类型或函数类型命名,使代码更加清晰。
  • 简化重复的类型定义,增强代码的可维护性。
type Point = {x: number;y: number;
};type Shape = "circle" | "square" | "rectangle";function drawShape(shape: Shape, position: Point): void {console.log(`Drawing a ${shape} at (${position.x}, ${position.y})`);
}drawShape("circle", { x: 10, y: 20 });
  • Point 是一个类型别名,表示具有 x 和 y 两个 number 类型属性的对象。
  • Shape 是一个由特定字符串字面量组成的联合类型别名。
  • drawShape 函数接受一个 Shape 和一个 Point 参数,确保了强类型安全性和代码的清晰性。

输出:

Drawing a circle at (10, 20)

1. 类型别名的参数:

AliasName(别名名称)
这是你为类型别名指定的名称,必须是有效的 TypeScript 标识符。
示例:PointShapeUserProfile

ExistingType(已有类型)
指的是该别名所代表的实际数据类型或结构。
示例:stringnumber{ x: number; y: number; }

2. 联合类型的别名

type ID = number | string;let userId: ID;
userId = 101;       // 有效的赋值
userId = "A123";    // 也是有效的赋值
  • ID 是一个类型别名,允许变量的类型为数字或字符串。
  • 这为 userId 提供了灵活性,使其既可以接受数字类型也可以接受字母数字混合的标识符。

输出:

Origin: { x: 0, y: 0 }
Distance from Origin: 0

3. 使用类型别名定义用户资料

type UserProfile = {username: string;email: string;age: number;
};const user: UserProfile = {username: "Felixlu",email: "lurongtao@pku.org.cn",age: 24,
};function greetUser(profile: UserProfile): string {return `Hello, ${profile.username}! You are ${profile.age} years old. Your email is ${profile.email}.`;
}console.log(greetUser(user));
  • UserProfile 是一个对象类型别名,包含 username、email 和 age 属性。
  • greetUser 函数使用该别名,确保接收的参数是结构正确的用户资料。

输出:

Hello, Felixlu! 
You are 24 years old. 
Your email is lurongtao@pku.org.cn.

4. 使用类型别名定义联合类型

type ID = number | string;function displayId(id: ID): void {console.log(`The ID is ${id}`);
}displayId(101);
displayId("A102");
  • ID 是一个类型别名,表示 number 和 string 的联合类型。
  • displayId 函数接受一个 ID 类型的参数,允许传入多种类型的值,增强了灵活性。

输出:

The ID is 101
The ID is A102

5. TypeScript 类型别名的最佳实践

  1. 使用描述性名称:选择清晰且有意义的类型别名名称,以提升代码的可读性。
  2. 保持类型聚焦:为特定且定义明确的结构定义类型别名,以保持代码清晰。
  3. 记录复杂类型:对复杂的类型别名添加注释或文档,帮助理解类型的具体含义。

(三) Keyof 类型

TypeScript 的 keyof 操作符用于获取某个对象类型中所有键名的联合类型。当你希望以类型安全的方式操作对象的属性名,确保只使用有效键时,它非常有用。

我们可以使用 keyof 来定义适用于任意对象类型的泛型函数,无需预先知道该类型的具体键名。它也可以用来创建接口的只读版本,或者从接口中提取特定的键。

1. 语法

type KeysOfType = keyof ObjectType;

2. 如何使用 keyof 类型操作符?

我们定义了一个包含三个不同属性的接口 Personnameagegender。然后我们定义了一个类型 PersonKeys,它等于 keyof Person,即一个 "name" | "age" | "gender" 的联合类型。

interface Person {name: string;age: number;gender: string;
}
type PersonKeys = keyof Person;

3. 展示 keyof 类型操作符的示例

让我们来看一些 TypeScript 中 keyof 类型操作符的示例。这些示例将帮助你理解 keyof 类型操作符的工作原理。

(1)访问对象属性

在此示例中,我们定义了一个包含三个属性(name、age 和 gender)的接口 Person。我们还定义了一个类型为 Person 的变量 person 并赋予一些值。

interface Person {name: string;age: number;gender: string;
}const person: Person = {name: "John",age: 25,gender: "male",
};function getProperty<T, K extends keyof T>(obj: T, key: K) {return obj[key];
}console.log(getProperty(person, "name")); // "John"
console.log(getProperty(person, "age")); // 25
console.log(getProperty(person, "gender")); // "male"

输出:

John
25
male

代码解释:

  • getProperty 接受一个类型为 T 的对象 obj 和一个键 K
  • 其中 K 是 T 的有效键(K extends keyof T),确保该键存在于对象中。
  • 该函数返回 obj[key] 对应的值。

(2)使用映射类型

在这个示例中,我们定义了一个包含三个属性 name、age 和 gender 的接口 Person。

interface Person {name: string;age: number;gender: string;
}type ReadonlyPerson = {readonly [K in keyof Person]: Person[K];
}const person: ReadonlyPerson = {name: "John",age: 25,gender: "male",
};console.log(person.name); // "John"
console.log(person.age); // 25
console.log(person.gender); // "male"

输出:

John
25
male

代码解释:

  • [K in keyof Person] 创建了键为 K、值类型为 Person[K] 的属性,但这些属性是只读的。
  • 类型 ReadonlyPerson 拥有从 Person 派生的不可变属性。
  • ReadonlyPerson 变量不能修改其属性。

相关文章:

4. TypeScript 类型推断与类型组合

一、类型推断 (一) 什么是类型推断 TypeScript 的类型推断会根据变量、函数返回值、对象和数组的赋值和使用方式&#xff0c;自动确定它们的类型。 这一特性减少了显式类型注解的需要&#xff0c;在保持类型安全的同时简化了代码。通过分析上下文和初始值&#xff0c;TypeSc…...

打手机检测算法AI智能分析网关V4守护公共/工业/医疗等多场景安全应用

一、方案背景​ 在现代生产与生活场景中&#xff0c;如工厂高危作业区、医院手术室、公共场景等&#xff0c;人员违规打手机的行为潜藏着巨大风险。传统依靠人工巡查的监管方式&#xff0c;存在效率低、覆盖面不足、判断主观性强等问题&#xff0c;难以满足对人员打手机行为精…...

[大语言模型]在个人电脑上部署ollama 并进行管理,最后配置AI程序开发助手.

ollama官网: 下载 https://ollama.com/ 安装 查看可以使用的模型 https://ollama.com/search 例如 https://ollama.com/library/deepseek-r1/tags # deepseek-r1:7bollama pull deepseek-r1:7b改token数量为409622 16384 ollama命令说明 ollama serve #&#xff1a…...

逻辑回归暴力训练预测金融欺诈

简述 「使用逻辑回归暴力预测金融欺诈&#xff0c;并不断增加特征维度持续测试」的做法&#xff0c;体现了一种逐步建模与迭代验证的实验思路&#xff0c;在金融欺诈检测中非常有价值&#xff0c;本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...

NPOI操作EXCEL文件 ——CAD C# 二次开发

缺点:dll.版本容易加载错误。CAD加载插件时&#xff0c;没有加载所有类库。插件运行过程中用到某个类库&#xff0c;会从CAD的安装目录找&#xff0c;找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库&#xff0c;就用插件程序加载进…...

FFmpeg:Windows系统小白安装及其使用

一、安装 1.访问官网 Download FFmpeg 2.点击版本目录 3.选择版本点击安装 注意这里选择的是【release buids】&#xff0c;注意左上角标题 例如我安装在目录 F:\FFmpeg 4.解压 5.添加环境变量 把你解压后的bin目录&#xff08;即exe所在文件夹&#xff09;加入系统变量…...

MySQL 部分重点知识篇

一、数据库对象 1. 主键 定义 &#xff1a;主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 &#xff1a;确保数据的完整性&#xff0c;便于数据的查询和管理。 示例 &#xff1a;在学生信息表中&#xff0c;学号可以作为主键&#xff…...

Git常用命令完全指南:从入门到精通

Git常用命令完全指南&#xff1a;从入门到精通 一、基础配置命令 1. 用户信息配置 # 设置全局用户名 git config --global user.name "你的名字"# 设置全局邮箱 git config --global user.email "你的邮箱example.com"# 查看所有配置 git config --list…...

[ACTF2020 新生赛]Include 1(php://filter伪协议)

题目 做法 启动靶机&#xff0c;点进去 点进去 查看URL&#xff0c;有 ?fileflag.php说明存在文件包含&#xff0c;原理是php://filter 协议 当它与包含函数结合时&#xff0c;php://filter流会被当作php文件执行。 用php://filter加编码&#xff0c;能让PHP把文件内容…...

Golang——9、反射和文件操作

反射和文件操作 1、反射1.1、reflect.TypeOf()获取任意值的类型对象1.2、reflect.ValueOf()1.3、结构体反射 2、文件操作2.1、os.Open()打开文件2.2、方式一&#xff1a;使用Read()读取文件2.3、方式二&#xff1a;bufio读取文件2.4、方式三&#xff1a;os.ReadFile读取2.5、写…...

从 GreenPlum 到镜舟数据库:杭银消费金融湖仓一体转型实践

作者&#xff1a;吴岐诗&#xff0c;杭银消费金融大数据应用开发工程师 本文整理自杭银消费金融大数据应用开发工程师在StarRocks Summit Asia 2024的分享 引言&#xff1a;融合数据湖与数仓的创新之路 在数字金融时代&#xff0c;数据已成为金融机构的核心竞争力。杭银消费金…...

比较数据迁移后MySQL数据库和OceanBase数据仓库中的表

设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...

R 语言科研绘图第 55 期 --- 网络图-聚类

在发表科研论文的过程中&#xff0c;科研绘图是必不可少的&#xff0c;一张好看的图形会是文章很大的加分项。 为了便于使用&#xff0c;本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中&#xff0c;获取方式&#xff1a; R 语言科研绘图模板 --- sciRplothttps://mp.…...

在鸿蒙HarmonyOS 5中使用DevEco Studio实现企业微信功能

1. 开发环境准备 ​​安装DevEco Studio 3.1​​&#xff1a; 从华为开发者官网下载最新版DevEco Studio安装HarmonyOS 5.0 SDK ​​项目配置​​&#xff1a; // module.json5 {"module": {"requestPermissions": [{"name": "ohos.permis…...

LabVIEW双光子成像系统技术

双光子成像技术的核心特性 双光子成像通过双低能量光子协同激发机制&#xff0c;展现出显著的技术优势&#xff1a; 深层组织穿透能力&#xff1a;适用于活体组织深度成像 高分辨率观测性能&#xff1a;满足微观结构的精细研究需求 低光毒性特点&#xff1a;减少对样本的损伤…...

Caliper 负载(Workload)详细解析

Caliper 负载(Workload)详细解析 负载(Workload)是 Caliper 性能测试的核心部分,它定义了测试期间要执行的具体合约调用行为和交易模式。下面我将全面深入地讲解负载的各个方面。 一、负载模块基本结构 一个典型的负载模块(如 workload.js)包含以下基本结构: use strict;/…...

【 java 虚拟机知识 第一篇 】

目录 1.内存模型 1.1.JVM内存模型的介绍 1.2.堆和栈的区别 1.3.栈的存储细节 1.4.堆的部分 1.5.程序计数器的作用 1.6.方法区的内容 1.7.字符串池 1.8.引用类型 1.9.内存泄漏与内存溢出 1.10.会出现内存溢出的结构 1.内存模型 1.1.JVM内存模型的介绍 内存模型主要分…...

(一)单例模式

一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...

day36-多路IO复用

一、基本概念 &#xff08;服务器多客户端模型&#xff09; 定义&#xff1a;单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用&#xff1a;应用程序通常需要处理来自多条事件流中的事件&#xff0c;比如我现在用的电脑&#xff0c;需要同时处理键盘鼠标…...

群晖NAS如何在虚拟机创建飞牛NAS

套件中心下载安装Virtual Machine Manager 创建虚拟机 配置虚拟机 飞牛官网下载 https://iso.liveupdate.fnnas.com/x86_64/trim/fnos-0.9.2-863.iso 群晖NAS如何在虚拟机创建飞牛NAS - 个人信息分享...

android13 app的触摸问题定位分析流程

一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...

MinIO Docker 部署:仅开放一个端口

MinIO Docker 部署:仅开放一个端口 在实际的服务器部署中,出于安全和管理的考虑,我们可能只能开放一个端口。MinIO 是一个高性能的对象存储服务,支持 Docker 部署,但默认情况下它需要两个端口:一个是 API 端口(用于存储和访问数据),另一个是控制台端口(用于管理界面…...

怎么让Comfyui导出的图像不包含工作流信息,

为了数据安全&#xff0c;让Comfyui导出的图像不包含工作流信息&#xff0c;导出的图像就不会拖到comfyui中加载出来工作流。 ComfyUI的目录下node.py 直接移除 pnginfo&#xff08;推荐&#xff09;​​ 在 save_images 方法中&#xff0c;​​删除或注释掉所有与 metadata …...

作为测试我们应该关注redis哪些方面

1、功能测试 数据结构操作&#xff1a;验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化&#xff1a;测试aof和aof持久化机制&#xff0c;确保数据在开启后正确恢复。 事务&#xff1a;检查事务的原子性和回滚机制。 发布订阅&#xff1a;确保消息正确传递。 2、性…...

Caliper 配置文件解析:fisco-bcos.json

config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...

第7篇:中间件全链路监控与 SQL 性能分析实践

7.1 章节导读 在构建数据库中间件的过程中&#xff0c;可观测性 和 性能分析 是保障系统稳定性与可维护性的核心能力。 特别是在复杂分布式场景中&#xff0c;必须做到&#xff1a; &#x1f50d; 追踪每一条 SQL 的生命周期&#xff08;从入口到数据库执行&#xff09;&#…...

基于PHP的连锁酒店管理系统

有需要请加文章底部Q哦 可远程调试 基于PHP的连锁酒店管理系统 一 介绍 连锁酒店管理系统基于原生PHP开发&#xff0c;数据库mysql&#xff0c;前端bootstrap。系统角色分为用户和管理员。 技术栈 phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 注册/登录/注销 2 个人中…...

解决:Android studio 编译后报错\app\src\main\cpp\CMakeLists.txt‘ to exist

现象&#xff1a; android studio报错&#xff1a; [CXX1409] D:\GitLab\xxxxx\app.cxx\Debug\3f3w4y1i\arm64-v8a\android_gradle_build.json : expected buildFiles file ‘D:\GitLab\xxxxx\app\src\main\cpp\CMakeLists.txt’ to exist 解决&#xff1a; 不要动CMakeLists.…...

Vite中定义@软链接

在webpack中可以直接通过符号表示src路径&#xff0c;但是vite中默认不可以。 如何实现&#xff1a; vite中提供了resolve.alias&#xff1a;通过别名在指向一个具体的路径 在vite.config.js中 import { join } from pathexport default defineConfig({plugins: [vue()],//…...

基于Java+VUE+MariaDB实现(Web)仿小米商城

仿小米商城 环境安装 nodejs maven JDK11 运行 mvn clean install -DskipTestscd adminmvn spring-boot:runcd ../webmvn spring-boot:runcd ../xiaomi-store-admin-vuenpm installnpm run servecd ../xiaomi-store-vuenpm installnpm run serve 注意&#xff1a;运行前…...