Typescript学习教程,从入门到精通,TypeScript 泛型与类型操作详解(二)(17)
TypeScript 泛型与类型操作详解(二)
本文将详细介绍 TypeScript 中的一些高级类型特性,包括条件类型、分布式条件类型、infer
关键字、内置工具类型、类型查询、类型断言、类型细化和类型守卫等。
1. 条件类型(Conditional Types)
1.1 定义
条件类型允许根据类型之间的关系在类型系统中进行条件判断。其语法类似于 JavaScript 中的三元运算符:
T extends U ? X : Y
- 解释: 如果类型
T
可以赋值给类型U
,则结果类型为X
,否则为Y
。
1.2 示例
type IsString<T> = T extends string ? true : false;type A = IsString<string>; // A 的类型为 true
type B = IsString<number>; // B 的类型为 false
2. 分布式条件类型(Distributive Conditional Types)
当条件类型应用于联合类型时,TypeScript 会将联合类型中的每个成员单独应用于条件类型,这种行为称为“分布式”。
2.1 示例
type ToArray<T> = T extends any ? T[] : never;type A = ToArray<string | number>; // A 的类型为 string[] | number[]
在这个例子中,ToArray
条件类型被应用于 string | number
,结果为 string[] | number[]
。
3. infer
关键字
infer
关键字用于在条件类型中推断类型。它通常用于提取类型的一部分,例如函数的返回类型或参数类型。
3.1 示例:提取函数返回类型
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;// 使用内置的 ReturnType
type Func = () => string;
type Result = ReturnType<Func>; // Result 的类型为 string
3.2 示例:提取数组元素类型
type ElementType<T> = T extends (infer E)[] ? E : T;type A = ElementType<string[]>; // A 的类型为 string
type B = ElementType<number>; // B 的类型为 number
4. 内置工具类型(Utility Types)
TypeScript 提供了一些内置的工具类型,简化常见的类型操作。以下是一些常用的工具类型及其示例。
4.1 Partial<T>
将类型 T
的所有属性设为可选。
interface User {id: number;name: string;age?: number;
}type PartialUser = Partial<User>;
// PartialUser 等同于:
// {
// id?: number;
// name?: string;
// age?: number;
// }
4.2 Required<T>
将类型 T
的所有属性设为必填。
type RequiredUser = Required<PartialUser>;
// RequiredUser 等同于:
// {
// id: number;
// name: string;
// age: number;
// }
4.3 Readonly<T>
将类型 T
的所有属性设为只读。
type ReadonlyUser = Readonly<User>;
// ReadonlyUser 等同于:
// {
// readonly id: number;
// readonly name: string;
// readonly age?: number;
// }
4.4 Record<K, T>
构造一个对象类型,其键为 K
,值为 T
。
type StringNumberMap = Record<string, number>;
// StringNumberMap 等同于:
// {
// [key: string]: number;
// }type UserRoles = Record<'admin' | 'user', boolean>;
// UserRoles 等同于:
// {
// admin: boolean;
// user: boolean;
// }
4.5 Pick<T, K>
从类型 T
中选取一组属性 K
构成新类型。
type PickUser = Pick<User, 'id' | 'name'>;
// PickUser 等同于:
// {
// id: number;
// name: string;
// }
4.6 Omit<T, K>
从类型 T
中排除一组属性 K
构成新类型。
type OmitUser = Omit<User, 'age'>;
// OmitUser 等同于:
// {
// id: number;
// name: string;
// }
4.7 Exclude<T, U>
从类型 T
中排除可赋值给 U
的部分。
type ExcludeString = Exclude<string | number | boolean, string | number>;
// ExcludeString 的类型为 boolean
4.8 Extract<T, U>
从类型 T
中提取可赋值给 U
的部分。
type ExtractString = Extract<string | number | boolean, string>;
// ExtractString 的类型为 string
4.9 NonNullable<T>
从类型 T
中排除 null
和 undefined
。
type NonNullableUser = NonNullable<User | null | undefined>;
// NonNullableUser 的类型为 User
4.10 Parameters<T>
提取函数类型 T
的参数类型组成的元组类型。
type Func = (a: string, b: number) => void;
type Params = Parameters<Func>;
// Params 的类型为 [string, number]
4.11 ConstructorParameters<T>
提取构造函数类型 T
的参数类型组成的元组类型。
type SomeClass = new (a: string, b: number) => void;
type ConstructorParams = ConstructorParameters<SomeClass>;
// ConstructorParams 的类型为 [string, number]
4.12 ReturnType<T>
提取函数类型 T
的返回类型。
type Func = () => string;
type Return = ReturnType<Func>;
// Return 的类型为 string
4.13 InstanceType<T>
提取构造函数类型 T
的实例类型。
type SomeClass = new () => { id: number };
type Instance = InstanceType<SomeClass>;
// Instance 的类型为 { id: number }
4.14 ThisParameterType<T>
提取函数类型 T
的 this
参数类型。
type FuncWithThis = (this: Date, x: string) => void;
type ThisParam = ThisParameterType<FuncWithThis>;
// ThisParam 的类型为 Date
4.15 OmitThisParameter<T>
移除函数类型 T
的 this
参数类型。
type FuncWithoutThis = OmitThisParameter<FuncWithThis>;
// FuncWithoutThis 的类型为 (x: string) => void
4.16 ThisType<T>
用于在对象字面量中指定 this
的上下文类型。
type ObjectWithThis = {id: number;getId(this: ObjectWithThis): number;
};const obj: ObjectWithThis = {id: 1,getId(this: ObjectWithThis) {return this.id;}
};
5. 类型查询(Type Queries)
类型查询使用 typeof
操作符来获取变量或属性的类型。
5.1 示例
let age = 25;
type AgeType = typeof age; // AgeType 的类型为 numberconst user = {id: 1,name: 'Alice'
};
type UserType = typeof user;
// UserType 的类型为 { id: number; name: string }
6. 类型断言(Type Assertions)
类型断言允许开发者手动指定一个值的类型,绕过 TypeScript 的类型检查。
6.1 <T>类型断言
let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;
6.2 as T
类型断言
let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;
6.3 类型断言的约束
类型断言不能违反类型层级。例如,不能将 number
断言为 string
。
6.4 const
类型断言
const
断言用于创建只读、字面量类型的值。
let x = "hello" as const;
// x 的类型为 "hello"let y = { id: 1, name: "Alice" } as const;
// y 的类型为 { readonly id: 1; readonly name: "Alice" }
6.5 !
类型断言
!
用于断言某个值不是 null
或 undefined
。
function getLength(s?: string) {return s!.length;
}
7. 类型细化(Type Narrowing)
类型细化是通过代码逻辑来缩小变量的类型范围,常用的方法包括类型守卫、赋值语句分析、控制流分析等。
7.1 类型守卫(Type Guards)
7.1.1 typeof
类型守卫
function printId(id: string | number) {if (typeof id === "string") {console.log(id.toUpperCase());} else {console.log(id.toFixed(2));}
}
7.1.2 instanceof
类型守卫
function printDate(date: Date | string) {if (date instanceof Date) {console.log(date.toUTCString());} else {console.log(date.toUpperCase());}
}
7.1.3 自定义类型守卫
interface Cat {meow(): void;
}interface Dog {bark(): void;
}function isCat(animal: Cat | Dog): animal is Cat {return (animal as Cat).meow !== undefined;
}function speak(animal: Cat | Dog) {if (isCat(animal)) {animal.meow();} else {animal.bark();}
}
7.2 赋值语句分析
通过赋值语句,TypeScript 可以推断出变量的更具体类型。
let x: string | number;
x = "hello";
// x 的类型被细化为 stringx = 123;
// x 的类型被细化为 number
7.3 基于控制流的类型分析
TypeScript 会根据控制流(如 if
、else
、return
等)来推断变量的类型。
function example(x: string | number) {if (typeof x === "string") {// x 的类型为 stringconsole.log(x.toUpperCase());} else {// x 的类型为 numberconsole.log(x.toFixed(2));}
}
7.4 断言函数(Assertion Functions)
断言函数用于在运行时验证类型,并在验证失败时抛出错误。
function assertIsString(val: any): asserts val is string {if (typeof val !== "string") {throw new Error("Value is not a string");}
}function printString(s: string | number) {assertIsString(s);console.log(s.toUpperCase());
}
8. 案例代码
8.1 使用 Partial
和 Pick
创建部分属性对象
interface User {id: number;name: string;age: number;email: string;
}function updateUser(user: User, updates: Partial<Pick<User, 'name' | 'email'>>) {return { ...user, ...updates };
}const alice: User = { id: 1, name: "Alice", age: 30, email: "alice@example.com" };
const updatedAlice = updateUser(alice, { name: "Alicia", email: "alicia@example.com" });
// updatedAlice 的类型为 User
8.2 使用 Exclude
和 Extract
进行类型操作
type Mixed = string | number | boolean | string[];type NonString = Exclude<Mixed, string>; // NonString 的类型为 number | boolean | string[]
type OnlyString = Extract<Mixed, string>; // OnlyString 的类型为 stringtype NonEmptyString = Exclude<OnlyString, ''>; // NonEmptyString 的类型为 string
8.3 使用 ReturnType
获取函数返回类型
type GreetFunc = (name: string) => string;type GreetReturn = ReturnType<GreetFunc>; // GreetReturn 的类型为 stringfunction greet(name: string): GreetReturn {return `Hello, ${name}!`;
}
8.4 使用 Parameters
获取函数参数类型
type SumFunc = (a: number, b: number) => number;type SumParams = Parameters<SumFunc>; // SumParams 的类型为 [number, number]function sum(a: number, b: number): number {return a + b;
}const params: SumParams = [1, 2];
8.5 使用 ThisParameterType
和 OmitThisParameter
处理 this
参数
type FuncWithThis = (this: Date, x: string) => void;type ThisParam = ThisParameterType<FuncWithThis>; // ThisParam 的类型为 Datetype FuncWithoutThis = OmitThisParameter<FuncWithThis>; // FuncWithoutThis 的类型为 (x: string) => voidfunction example(this: ThisParam, x: string) {console.log(this.toUTCString(), x);
}const date = new Date();
example.call(date, "hello");
8.6 使用 ThisType
在对象字面量中指定 this
类型
type ObjectWithThis = {id: number;getId(this: ObjectWithThis): number;
};const obj: ObjectWithThis = {id: 1,getId(this: ObjectWithThis) {return this.id;}
};console.log(obj.getId());
8.7 使用 is
进行自定义类型守卫
interface Cat {meow(): void;
}interface Dog {bark(): void;
}function isCat(animal: Cat | Dog): animal is Cat {return (animal as Cat).meow !== undefined;
}function speak(animal: Cat | Dog) {if (isCat(animal)) {animal.meow();} else {animal.bark();}
}const cat: Cat = { meow: () => console.log("Meow!") };
const dog: Dog = { bark: () => console.log("Woof!") };speak(cat); // 输出: Meow!
speak(dog); // 输出: Woof!
8.8 使用 const
断言创建只读对象
const config = {apiUrl: "https://api.example.com",timeout: 3000
} as const;type ConfigType = typeof config;
// ConfigType 的类型为:
// {
// readonly apiUrl: "https://api.example.com";
// readonly timeout: 3000;
// }
8.9 使用 NonNullable
排除 null
和 undefined
type MaybeString = string | null | undefined;type DefiniteString = NonNullable<MaybeString>; // DefiniteString 的类型为 stringfunction getString(): MaybeString {return "Hello";
}const str: DefiniteString = getString()!;
8.10 使用 InstanceType
获取构造函数实例类型
class Person {constructor(public name: string) {}
}type PersonConstructor = typeof Person;type PersonInstance = InstanceType<PersonConstructor>; // PersonInstance 的类型为 Personconst person: PersonInstance = new Person("Alice");
总结
TypeScript 提供了丰富的类型操作工具,使得开发者能够在编译阶段进行更严格的类型检查和更灵活的类型操作。通过理解和应用这些高级类型特性,可以显著提升代码的可维护性和可靠性。
相关文章:
Typescript学习教程,从入门到精通,TypeScript 泛型与类型操作详解(二)(17)
TypeScript 泛型与类型操作详解(二) 本文将详细介绍 TypeScript 中的一些高级类型特性,包括条件类型、分布式条件类型、infer 关键字、内置工具类型、类型查询、类型断言、类型细化和类型守卫等。 1. 条件类型(Conditional Type…...

【iOS】源码阅读(五)——类类的结构分析
文章目录 前言类的分析类的本质objc_class 、objc_object和NSObjectobjc_object:所有对象的基类型objc_class:类的底层结构NSObject:面向用户的根类 小结 指针内存偏移普通指针----值拷贝对象----指针拷贝或引用拷贝用数组指针引出----内存偏…...

基于CangjieMagic的RAG技术赋能智能问答系统
目录 引言 示例程序分析 代码结构剖析 导入模块解读 智能体配置详情 提示词模板说明 主程序功能解析 异步聊天功能实现 检索信息展示 技术要点总结 ollama 本地部署nomic-embed-text 运行测试 结语 引言 这段时间一直在学习CangjieMagic。前几天完成了在CangjieMa…...

算力租赁革命:弹性模式如何重构数字时代的创新门槛
一、算力革命:第四次工业革命的核心驱动力 在科技飞速发展的当下,我们正悄然迎来第四次工业革命。华为创始人任正非在一场程序设计竞赛中曾深刻指出,这场革命的基础便是大算力。随着 5G、人工智能、大数据、物联网等信息技术的迅猛发展&am…...

图论回溯
图论 200.岛屿数量DFS 给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。此外ÿ…...
使用arthas热替换在线运行的java class文件
如果我们在线的系统有问题,但又无法停机进行发版或者仅仅改了一个java文件需要验证一下功能是否正常,这时可以使用arthas的在线热替换功能来做class文件的在线变更。 1.运行java -jar arthas-boot.jar,启动arathas,并选择正在运行的java的进…...

RFID测温芯片助力新能源产业安全与能效提升
在“双碳”目标驱动下,新能源产业正经历爆发式增长。无论是电动汽车、储能电站还是风光发电场,设备安全与能效提升始终是行业核心命题。而温度,这个看似普通的物理参数,却成为破解这一命题的关键密码。RFID测温芯片(集…...

S32K3 工具篇9:如何在无源码情况下灵活调试elf文件
S32K3 工具篇9:如何在无源码情况下灵活调试elf文件 一,文档简介二, 功能实现2.1 代码工具准备2.2 elf修改功能实现:Fun2功能跳过2.2.1 PC越过Fun22.2.2 Fun2替换为nop 2.3 elf修改功能实现:Fun4替换Fun2入口2.3.1 link…...

Nacos 配置文件总结
Nacos 配置文件总结 文章目录 Nacos 配置文件总结1 、在 Nacos 服务端添加配置文件1. 启动Nacos Server。2. 新建配置文件。3. 发布配置集后,我们便可以在配置列表中查看相应的配置文件。4. 配置nacos数据库5. 运行 Nacos 容器6. 验证安装结果7. 配置验证 2 、在 Na…...

ASP.NET Web Forms框架识别
ASP.NET 支持三种不同的开发模式: Web Pages(Web 页面)、MVC(Model View Controller 模型-视图-控制器)、Web Forms(Web 窗体): Web Pages 单页面模式MVC 模型-视图-控制器Web Form…...
LG P4119 [Ynoi2018] 未来日记 Solution
Description 给定序列 a ( a 1 , a 2 , ⋯ , a n ) a(a_1,a_2,\cdots,a_n) a(a1,a2,⋯,an),有 m m m 个操作分两种: replace ( l , r , x , y ) \operatorname{replace}(l,r,x,y) replace(l,r,x,y):将 a l ∼ a r a_l\sim a_r …...
流程引擎选型指南
流程引擎选型指南 流程引擎是企业实现业务流程自动化(BPM)的核心组件,选择合适的流程引擎对系统架构和未来发展至关重要。以下是主流流程引擎的综合对比和选型建议。 一、主流流程引擎对比 引擎名称开源/商业BPMN支持DMN支持CMMN支持云原生支持社区活跃度学习曲线…...
基于大模型预测带状疱疹(无并发症)诊疗方案的研究报告
目录 一、引言 1.1 研究背景与意义 1.2 研究目的与创新点 二、带状疱疹概述 2.1 病因与发病机制 2.2 流行病学特征 2.3 临床表现与诊断标准 三、大模型技术原理及应用于带状疱疹预测的可行性 3.1 大模型技术简介 3.2 应用可行性分析 四、大模型预测带状疱疹的具体方…...

哈工大计统大作业-程序人生
摘 要 本项目以“程序人生-Hellos P2P”为核心,通过编写、预处理、编译、汇编、链接及运行一个简单的Hello程序,系统探讨了计算机系统中程序从代码到进程的全生命周期。实验基于Ubuntu环境,使用GCC工具链完成代码转换,分析了预处…...

设计模式——装饰器设计模式(结构型)
摘要 文中主要介绍了装饰器设计模式,它是一种结构型设计模式,可在不改变原有类代码的情况下,动态为对象添加额外功能。文中详细阐述了装饰器模式的角色、结构、实现方式、适合场景以及实战示例等内容,还探讨了其与其他设计模式的…...

途景VR智拍APP:开启沉浸式VR拍摄体验
在数字化时代,VR技术以其沉浸式的体验逐渐走进了人们的日常生活。途景VR智拍APP作为一款集看图和拍照于一体的VR软件,为用户带来了全新的视觉体验和便捷的拍摄方式,无论是专业摄影师还是普通用户,都能轻松上手,拍出令人…...

Linux环境搭建MCU开发环境
操作系统版本: ubuntu 22.04 文本编辑器: vscode 开发板: stm32f103c8t6 调试器: st-link 前言 步骤一: 安装交叉编译工具链 步骤二: 创建工程目录结构 步骤三: 调试…...
Android高级开发第一篇 - JNI(初级入门篇)
文章目录 Android高级开发JNI开发第一篇(初级入门篇)🧠 一、什么是 JNI?✅ 为什么要用 JNI? ⚙️ 二、开发环境准备开发工具 🚀 三、创建一个支持 JNI 的 Android 项目第一步:创建新项目项目结构…...
Kubernetes RBAC权限控制:从入门到实战
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 引言:为什么需要RBAC? 在Kubernetes集群中,权限失控是导致安全漏洞的核心原因之一。试想以下场景: 开发…...
python实战项目71:基于Python的US News世界大学排名数据爬取
python实战项目71:基于Python的US News世界大学排名数据爬取 一、项目背景1.1 研究意义1.2 技术背景1.3 应用场景二、爬虫系统设计与实现2.1 分析页面、寻找数据真实接口2.2 发送请求,获取响应内容2.3 提取数据2.4 保存数据三、完整代码四、总结与展望一、项目背景 1.1 研究…...

【基础算法】高精度(加、减、乘、除)
文章目录 什么是高精度1. 高精度加法解题思路代码实现 2. 高精度减法解题思路代码实现 3. 高精度乘法解题思路代码实现 4. 高精度除法 (高精度 / 低精度)解题思路代码实现 什么是高精度 我们平时使用加减乘除的时候都是直接使用 - * / 这些符号,前提是进行运算的数…...
跨平台开发框架electron
桌面端开发框架有很多,比如C#的WPF和Winform,Dart的Flutter,JS的Electron,Rust的Tauri。 目前应用比较广的是Electron,比如我们常见的开发工具VsCode,就是基于Electron开发的。 所以这篇文章我们就来聊聊Electron。 简…...

Windows最快速打开各项系统设置大全
目录 一、应用背景 二、设置项打开方法 2.1 方法一界面查找(最慢) 2.2 方法二cmd命令(慢) 2.3 方法三快捷键(快) 2.4 方法四搜索栏(快) 2.5 方法五任务栏(最快&am…...

嵌入式编译工具链熟悉与游戏移植
在自己的虚拟机Ubuntu系统下,逐步编译 mininim源码(波斯王子重制开源版) 指令流程 sudo apt-get remove liballegro5-dev liballegro-image5-dev \liballegro-audio5-dev liballegro-acodec5-dev liballegro-dialog5-dev sudo apt-get install automak…...

DeepSeek-R1-0528,官方的端午节特别献礼
DeepSeek:端午安康!刻在国人骨子里的浪漫 2025 年 05 月 28 日 | DeepSeek 端午特别献礼 当粽叶飘香时,DeepSeek 悄然带来一份节日惊喜 版本号 DeepSeek-R1-0528 正式上线 官方赋予它的灵魂是: 思考更深 推理更强 用户通过官网…...
LNMP环境中php7.2升级到php7.4
以下是 CentOS 7 上从 PHP 7.2 升级到 PHP 7.4 的详细步骤,结合知识库中的方法和注意事项: 1.备份现有环境 #备份 PHP 配置文件 cp /etc/php.ini /etc/php.ini.bak cp -r /etc/php.d /etc/php.d.bak#备份网站文件和数据库 tar -czvf website_backup.tar…...

001 flutter学习的注意事项及前期准备
在学习flutter之前,还需要进行一些初始的配置,然后才可以学习flutter 1.安装flutter 国内官网:https://flutter.cn 国际官网:https://flutter.dev 安装完成后,按照官网上面的操作步骤进行配置…...
FactoryBean 接口
Spring 框架中 FactoryBean 接口的特性,这是 Spring 提供的一种特殊机制,用于创建和管理复杂 Bean。让我通过示例和解释帮您理解这个概念。 一、FactoryBean 是什么? FactoryBean 是 Spring 框架提供的一个工厂接口,用于创建复杂…...

CS144 - Lecture 1 记录
CS144 - Lecture 1 由于没讲义,全看课了,系统性的总结有点难,记一些有趣的东西吧。 数据链路和网络层的传输 我们可以看见,对于发送方,我们的数据链路层为我们的网络层提供服务,在经过路由的时候…...
【Redis】大key问题详解
目录 1、什么是大key2、大key的危害【1】阻塞风险【2】网络阻塞【3】内存不均【4】持久化问题 3、如何发现大key【1】使用内置命令【2】使用memory命令(Redis 4.0)【3】使用scan命令【4】监控工具 4、解决方案【1】拆分大key【2】使用合适的数据结构【3】…...