Typescript高级: 深入理解extends keyof语法

2024-06-03 02:04

本文主要是介绍Typescript高级: 深入理解extends keyof语法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

概述

  • 在TypeScript中,extends关键字是类型系统中一个极其重要的组成部分
  • 它不仅用于类的继承,也是类型兼容性检查和泛型约束的关键机制
  • 特别是当它与keyof关键字结合,形成K extends keyof T的结构时
  • 它为类型系统带来了强大的灵活性和表达能力,让我们能够在泛型中对对象的属性进行操作和约束

K extends keyof T

  • 在TypeScript中,当你声明一个泛型约束为K extends keyof T
  • 这意味着泛型参数K被限制为只能是T类型上存在的属性名的子集
  • 这在处理对象属性、映射类型或者条件类型时非常有用

示例1

interface User {id: number;name: string;email: string;
}function getProperty<T, K extends keyof T>(user: T, key: K): T[K] {return user[key];
}const user = { id: 1, name: "Alice", email: "alice@example.com"};
console.log(getProperty(user, "name")); // 输出 "Alice"
  • 在这个例子中,K extends keyof User 确保了getProperty函数的key参数, 只能是User接口中定义的属性名

示例2 属性全面转化成只读

interface User {id: number;name: string;email: string;
}type ReadonlyStringFields<T> = {readonly [P in keyof T]: T[P];}type ReadonlyUser = ReadonlyStringFields<User>;// ReadonlyUser 类型为:
// {
//   id: number;
//   readonly name: string;
//   readonly email: string;
// }
  • 这里,ReadonlyStringFields 将所有属性转化为只读,当然

示例3:部分属性只读

type MakeSomePropertiesReadonly<T, K extends keyof T> = {readonly [P in K]: T[P];
} & {[P in Exclude<keyof T, K>]: T[P];
};interface UserInfo {id: number;username: string;email: string;isAdmin: boolean;
}type ReadonlyUserDetails = MakeSomePropertiesReadonly<UserInfo, 'id' | 'email'>;function displayUserInfo(user: ReadonlyUserDetails) {console.log(`ID: ${user.id}, Email: ${user.email}`);// 下面这行如果尝试在真实代码中执行,会因为类型检查而在编译时失败// user.id = 123; // Error: Cannot assign to 'id' because it is a read-only property.user.username = "NewUsername"; // 这是允许的,因为 username 不是只读的
}// 假设我们有一个UserInfo实例,为了演示,直接构造一个符合 ReadonlyUserDetails 的对象
const userDetails: ReadonlyUserDetails = {id: 42,username: "JohnDoe",email: "john.doe@example.com",isAdmin: false,
};displayUserInfo(userDetails);
  • 在 MakeSomePropertiesReadonly<T, K>
  • 泛型参数:
    • T: 表示你想要修改属性可读性的原始对象类型
    • K extends keyof T: 表示一个泛型约束,要求 K 必须是 T 类型的键(即属性名)的一个子集。这意味着你可以指定 T 中任意数量和名称的属性来变为只读
  • 类型别名结构:
    • { readonly [P in K]: T[P]; }: 这部分创建了一个新类型,其中 K 集合内的每个属性 P 被声明为只读。[P in K] 是一个映射类型,遍历 K 中的所有键,并为每个键创建一个属性,其值类型与 T[P] 相同,但加上了 readonly 修饰符。
    • & { [P in Exclude<keyof T, K>]: T[P]; } 这部分用来保留 T 类型中未被指定为只读的那些属性。Exclude<keyof T, K> 是一个实用类型,用于从 T 的所有键中排除已经在 K 中的键,确保剩余的属性不被重复定义且保持原样。

K extends keyof any

  • 当K extends keyof any时,这个约束实际上没有起到任何限制作用
  • 因为any类型在TypeScript中是最宽泛的类型,表示可以代表任何类型,所以任何类型都可以被认为是any的键
  • 这通常在你想要泛型参数可以是任何类型时使用,但这种用法在实践中较少见,因为失去了类型安全性的优势

示例

function getProperty<K extends keyof any>(obj: any, key: K): any {  return obj[key];  
}  const person = {  name: 'Alice',  age: 30,  address: '123 Main Street'  
};  // 由于使用了 keyof any,我们可以传入任何类型的键  
const name = getProperty(person, 'name'); // string  
const age = getProperty(person, 'age'); // number  
const address = getProperty(person, 'address'); // string  
const unknownProp = getProperty(person, 'unknownProp'); // undefined,但不会引发类型错误  console.log(name); // 输出: Alice  
console.log(age); // 输出: 30  
console.log(address); // 输出: 123 Main Street  
console.log(unknownProp); // 输出: undefined
  • keyof any表示任何可能的属性名,因为any类型可以包含任意属性
  • 使用K extends keyof any实际上对K没有太多限制,它可以是任意字符串或符号
  • 这种约束通常不是很有用,因为它不提供关于K具体可能是什么的明确信息

K extends keyof (string | number | symbol)

  • 这个表达式意味着泛型参数K可以是string或symbol类型中任何一个的键名
  • 在TypeScript中,对象的键通常是字符串或符号类型,但不包括数字(除非使用了计算属性名)
  • 因此,这个约束在直觉上可能用于处理特殊情况,比如当你知道泛型参数可能被用于索引一个映射到字符串或符号属性上,但实际上在标准对象操作中,数字作为键的用法不常见

示例

type AcceptableKeys = string | number | symbol;  function processKey<K extends AcceptableKeys>(key: K): void {console.log(`Processing key: ${key.toString()}`);  
}  // 使用字符串作为键  
processKey("myStringKey");  
// 使用数字作为键  
processKey(123);  // 使用符号作为键  
const mySymbol = Symbol("mySymbol");  
processKey(mySymbol);
  • 在这个示例中,我们定义了一个类型别名 AcceptableKeys,它表示可以接受的键类型是字符串、数字或符号
  • 然后,我们定义了一个泛型函数 processKey,它接受一个类型为 K 的参数,其中 K 被约束为必须扩展(extends)AcceptableKeys
  • 这样,我们就可以向 processKey 函数传递字符串、数字或符号类型的参数

这篇关于Typescript高级: 深入理解extends keyof语法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1025726

相关文章

深入理解C++ 空类大小

《深入理解C++空类大小》本文主要介绍了C++空类大小,规定空类大小为1字节,主要是为了保证对象的唯一性和可区分性,满足数组元素地址连续的要求,下面就来了解一下... 目录1. 保证对象的唯一性和可区分性2. 满足数组元素地址连续的要求3. 与C++的对象模型和内存管理机制相适配查看类对象内存在C++中,规

Python中列表的高级索引技巧分享

《Python中列表的高级索引技巧分享》列表是Python中最常用的数据结构之一,它允许你存储多个元素,并且可以通过索引来访问这些元素,本文将带你深入了解Python列表的高级索引技巧,希望对... 目录1.基本索引2.切片3.负数索引切片4.步长5.多维列表6.列表解析7.切片赋值8.删除元素9.反转列表

正则表达式高级应用与性能优化记录

《正则表达式高级应用与性能优化记录》本文介绍了正则表达式的高级应用和性能优化技巧,包括文本拆分、合并、XML/HTML解析、数据分析、以及性能优化方法,通过这些技巧,可以更高效地利用正则表达式进行复杂... 目录第6章:正则表达式的高级应用6.1 模式匹配与文本处理6.1.1 文本拆分6.1.2 文本合并6

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

认识、理解、分类——acm之搜索

普通搜索方法有两种:1、广度优先搜索;2、深度优先搜索; 更多搜索方法: 3、双向广度优先搜索; 4、启发式搜索(包括A*算法等); 搜索通常会用到的知识点:状态压缩(位压缩,利用hash思想压缩)。

深入探索协同过滤:从原理到推荐模块案例

文章目录 前言一、协同过滤1. 基于用户的协同过滤(UserCF)2. 基于物品的协同过滤(ItemCF)3. 相似度计算方法 二、相似度计算方法1. 欧氏距离2. 皮尔逊相关系数3. 杰卡德相似系数4. 余弦相似度 三、推荐模块案例1.基于文章的协同过滤推荐功能2.基于用户的协同过滤推荐功能 前言     在信息过载的时代,推荐系统成为连接用户与内容的桥梁。本文聚焦于

【生成模型系列(初级)】嵌入(Embedding)方程——自然语言处理的数学灵魂【通俗理解】

【通俗理解】嵌入(Embedding)方程——自然语言处理的数学灵魂 关键词提炼 #嵌入方程 #自然语言处理 #词向量 #机器学习 #神经网络 #向量空间模型 #Siri #Google翻译 #AlexNet 第一节:嵌入方程的类比与核心概念【尽可能通俗】 嵌入方程可以被看作是自然语言处理中的“翻译机”,它将文本中的单词或短语转换成计算机能够理解的数学形式,即向量。 正如翻译机将一种语言

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

【C++高阶】C++类型转换全攻略:深入理解并高效应用

📝个人主页🌹:Eternity._ ⏩收录专栏⏪:C++ “ 登神长阶 ” 🤡往期回顾🤡:C++ 智能指针 🌹🌹期待您的关注 🌹🌹 ❀C++的类型转换 📒1. C语言中的类型转换📚2. C++强制类型转换⛰️static_cast🌞reinterpret_cast⭐const_cast🍁dynamic_cast 📜3. C++强制类型转换的原因📝

深入手撕链表

链表 分类概念单链表增尾插头插插入 删尾删头删删除 查完整实现带头不带头 双向链表初始化增尾插头插插入 删查完整代码 数组 分类 #mermaid-svg-qKD178fTiiaYeKjl {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-