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

news2025/6/12 8:47:12

一、类型推断

(一) 什么是类型推断

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 变量不能修改其属性。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

打手机检测算法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;本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…

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

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

[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;数据已成为金融机构的核心竞争力。杭银消费金…

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

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

LabVIEW双光子成像系统技术

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

【 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指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…

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

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

基于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;运行前…

MacOS下Homebrew国内镜像加速指南(2025最新国内镜像加速)

macos brew国内镜像加速方法 brew install 加速formula.jws.json下载慢加速 &#x1f37a; 最新版brew安装慢到怀疑人生&#xff1f;别怕&#xff0c;教你轻松起飞&#xff01; 最近Homebrew更新至最新版&#xff0c;每次执行 brew 命令时都会自动从官方地址 https://formulae.…

Qemu arm操作系统开发环境

使用qemu虚拟arm硬件比较合适。 步骤如下&#xff1a; 安装qemu apt install qemu-system安装aarch64-none-elf-gcc 需要手动下载&#xff0c;下载地址&#xff1a;https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x…

STM32---外部32.768K晶振(LSE)无法起振问题

晶振是否起振主要就检查两个1、晶振与MCU是否兼容&#xff1b;2、晶振的负载电容是否匹配 目录 一、判断晶振与MCU是否兼容 二、判断负载电容是否匹配 1. 晶振负载电容&#xff08;CL&#xff09;与匹配电容&#xff08;CL1、CL2&#xff09;的关系 2. 如何选择 CL1 和 CL…

Python 实现 Web 静态服务器(HTTP 协议)

目录 一、在本地启动 HTTP 服务器1. Windows 下安装 node.js1&#xff09;下载安装包2&#xff09;配置环境变量3&#xff09;安装镜像4&#xff09;node.js 的常用命令 2. 安装 http-server 服务3. 使用 http-server 开启服务1&#xff09;使用 http-server2&#xff09;详解 …