TypeScript类型体操5
类型编程主要的目的就是对类型做各种转换,如何对类型做修改?
TypeScript 类型系统支持 3 种可以声明任意类型的变量: type、infer、类型参数。
- type:类型别名,声明一个变量存储某个类型。
type t = Promise<number> - infer:用于提取类型,存到声明的变量里。
type GetValueType<P> = P extends Promise<infer Value> ? Value : never; - 类型参数:用于接受具体类型。
type isTwo<T> = T extends 2 ? true: false;
但是上述三种’变量’不是通常我们理解的变量,因为不能被重新赋值。但是做类型编程是为了能够产生各种负责的类型,因此只有通过重新构造来产生新类型。
重新构造
TypeScript 的 type、infer、类型参数声明的变量都不能修改,想对类型做各种变换产生新的类型就需要重新构造。
数组类型重新构造
添加类型
当我们声明了一个元组变量后,需要给这个元组类型添加新类型时:
//在最后添加 push
type tuple = [1,2,3];type Push<Arr extends unknown[], Ele> = [...Arr, Ele];type result = Push<[1,2,3],4>//[1,2,3,4]//在最前面添加 unshifttype Unshift<Arr extends unknown[], Ele> = [Ele, ...Arr];type result2 = Unshift<[1,2,3],0>
复杂案例
构造要求:
将已有的两个元组类型合并成一个新的元组类型
type tuple1 = [1,2];
type tuple2 = ['hello','world'];//合并后
type tuple = [[1,'hello'],[2,'world']];
思路:提取元组中的两个元素,构造成新的元组
type Zip<One extends [unknown,unknown], Other extends [unknown,unknown]> = One extends [infer OenFirst, infer OneSecond] ? Other extends [infer OtherFirst, infer OtherSecond]? [[OneFirst, OtherFirst],[OneSecond, OtherSecond]] : []: [];type result = Zip<tuple1,tuple2>;//[[1,'hello'],[2,'world']]
- 两个类型参数 One、Other 是两个元组,类型是 [unknown, unknown],代表 2 个任意类型的元素构成的元组
- 通过 infer 分别提取 One 和 Other 的元素到 infer 声明的局部变量 OneFirst、OneSecond、OtherFirst、OtherSecond 里
- 用提取的元素构造成新的元组返回
同理,尝试一下合并任意各元素的元组,使用递归的方式:
type Zip2<One extends unknown[], Other extends unknown[]> = One extends [infer OneFirst, ...infer OneRest]? Other extends [infer OtherFirst, ...infer OtherRest]? [[OneFirst,OtherFirst], ...Zip2<OneRest,OtherRest>] : []: [];
- 类型参数 One、Other 声明为 unknown[],也就是元素个数任意,类型任意的数组
- 每次提取 One 和 Other 的第一个元素 OneFirst、OtherFirst,剩余的放到 OneRest、OtherRest 里
- 用 OneFirst、OtherFirst 构造成新的元组的一个元素,剩余元素继续递归处理 OneRest、OtherRes
字符串类型的重新构造
思路:从已有字符串类型中提取部分字符串,经过一系列变换,构造成新的字符串类型
CapitalizeStr
将一个字符串字面量类型的’hello’转为首字母大写的’Hello’:
type CapitalizeStr<Str extends string> = Str extends `${infer First}${infer Rest}` ? `${Uppercase<First>}${Rest}` : Str;type result = CapitalizeStr<'hello'>
- 声明了类型参数 Str 是要处理的字符串类型,通过 extends 约束为 string
- 通过 infer 提取出首个字符到局部变量 First,提取后面的字符到局部变量 Rest
- 使用 TypeScript 提供的内置高级类型 Uppercase 把首字母转为大写,加上 Rest,构造成新的字符串类型返回
CamelCase
将一个how_are_you重新构造为howAreYou:
type CamelCase<Str extends string> = Str extends `${infer Left}_${infer Right}${infer Rest}` ? `${Left}${Uppercase<Right>}${CamelCase<Rest>}` : Str;
- 类型参数 Str 是待处理的字符串类型,约束为 string
- 提取 _ 之前和之后的两个字符到 infer 声明的局部变量 Left 和 Right,剩下的字符放到 Rest 里
- 然后把右边的字符 Right 大写,和 Left 构造成新的字符串,剩余的字符 Rest 要继续递归的处理
DropSubStr
删除字符串中的某个子串:
type DropSubStr<Str extends string, SubStr extends string> = Str extends `${infer Prefix}${SubStr}${infer Suffix}` ? DropSubStr<`${Prefix}${Suffix}`,SubStr> : Str;type result = DropSubStr<'hello,,,,,',','>//hello
- 类型参数 Str 是待处理的字符串, SubStr 是要删除的字符串,都通过 extends 约束为 string 类型
- 通过模式匹配提取 SubStr 之前和之后的字符串到 infer 声明的局部变量 Prefix、Suffix 中
- 如果匹配,那就用 Prefix、Suffix 构造成新的字符串,然后继续递归删除 SubStr。直到不再匹配,也就是没有 SubStr 了
函数类型的重新构造
我们可以提取函数的参数类型和返回值类型,当然可以将提取出的类型做修改后再构造出一个新的函数类型。
AppendArgument
在已有的函数类型上添加一个参数:
type AppendArgument<Func extends Function, Arg> = Func extends (...args: infer Args) => infer ReturnType ? (...args:[...Args,Arg]) => ReturnType : never;type result = AppendArgument<(name: string) => boolean,number>//(args_0:string, args_1:number) => boolean;
- 类型参数 Func 是待处理的函数类型,通过 extends 约束为 Function,Arg 是要添加的参数类型
- 通过模式匹配提取参数到 infer 声明的局部变量 Args 中,提取返回值到局部变量 ReturnType 中
- 用 Args 数组添加 Arg 构造成新的参数类型,结合 ReturnType 构造成新的函数类型返回
索引类型的重新构造
索引类型是聚合多个元素的类型,类似于class,对象等都是索引类型,对它的修改和构造新类型涉及到了映射类型的语法:
type obj = {name: string;age: number;gender: boolean;
}type Mapping<Obj extends object> = { [Key in keyof Obj]: Obj[Key]
}
Mapping
映射过程中对value做修改:
type Mapping<Obj extends object> = {[Key in keyof Obj]: [Obj[key],Obj[key],Obj[key]]
}type result = Mapping<{a:1,b:2}>;//{a:[1,1,1],b:[2,2,2]}
UppercaseKey
对Key做修改,使用as:
type UppercaseKey<Obj extends object> = {[Key in keyof Obj as Uppercase<Key & string>] : Obj[Key]
}type result = UppercaseKey<{a:1,b:2}>//{A:1,B:2}
Record
TypeScript 提供了内置的高级类型 Record 来创建索引类型
type Record<K extends string | number | symbol, T> = {[P in K]:T}
- 指定索引和值的类型分别为 K 和 T,就可以创建一个对应的索引类型
将上面的类型约束修改一下,约束类型参数 Obj 为 key 为 string,值为任意类型的索引类型:
type UppercaseKey<Obj extends Record<string, any>> = {[Key in keyof Obj as Uppercase<Key & string>] : Obj[Key]
}type result = UppercaseKey<{a:1,b:2}>//{A:1,B:2}
ToReadonly
索引类型的索引可以添加 readonly 的修饰符,代表只读,实现给索引类型添加readonly修饰符:
type ToReadonly<T> = {readonly [Key in keyof T]: T[Key];
}
- 通过映射类型构造了新的索引类型,给索引加上了 readonly 的修饰,其余的保持不变
同理,也可以用相同的方式给索引类型加可选修饰符:
type ToPartial<T> = {[Key in keyof T]?: T[Key]
}
ToMutable
给索引类型去掉只读修饰符:
type ToMutable<T> = {-readonly [Key in keyof T]: T[Key]
}
同理,去掉可选修饰符:
type ToRequired<T> = {[Key in keyof T]-?: T[Key]
}
FilterByValueType
在构造新索引类型的时候根据值的类型做过滤:
type FilterByValueType<Obj extends Record<string,any>, ValueType> = {[Key in keyof Obj as Obj[Key] extends ValueType ? Key : never] : Obj[Key];
}interface Person{name: string;age: number;hobby: string[];
}type result = FilterByValueType<Person, string | number> // {name:string; age: number;}
- 类型参数 Obj 为要处理的索引类型,通过 extends 约束为索引为 string,值为任意类型的索引类型 Record<string, any>
- 类型参数 ValueType 为要过滤出的值的类型
- 构造新的索引类型,索引为 Obj 的索引,也就是 Key in keyof Obj,但要做一些变换,也就是 as 之后的部分
- 如果原来索引的值 Obj[Key] 是 ValueType 类型,索引依然为之前的索引 Key,否则索引设置为 never,never 的索引会在生成新的索引类型时被去掉
- 值保持不变,依然为原来索引的值,也就是 Obj[Key]
相关文章:
TypeScript类型体操5
类型编程主要的目的就是对类型做各种转换,如何对类型做修改? TypeScript 类型系统支持 3 种可以声明任意类型的变量: type、infer、类型参数。 type:类型别名,声明一个变量存储某个类型。type t Promise<number&g…...
搭建广告展示页Start
想自定义广告- 场景: app冷启动/热启动-有广告需求,就打开广告页,没有的话就去登录或者主页 有的app有的需要广告页,有的不需要,搞个配置呗!!! 通过首选项配置存储我们的一些常用…...
无极低码基础版(部署版)课程计划
基础版(部署版)使用指南 特点 简单:1分钟学会无需编码:会SQL即可适合人群:纯小白0代码写服务1. 本地环境安装 JDKMySQLRedisTomcat2. 环境变量配置 JDK无极低码授权3. 配置文件修改 4. 服务启动 5. 服务发布示例 服务手动注册SQL语句注册6. 新增接口示例 正常新增非空参…...
Word文档功能快捷键大全
以下是 Microsoft Word 的全面快捷键大全,涵盖了文档操作、文本编辑、格式化、导航等多种功能,帮助你提高工作效率。 Word 全面快捷键和快捷方式表 功能类别快捷键/快捷方式功能描述基本文档操作Ctrl N新建文档Ctrl O打开文档Ctrl S保存文档F12另存…...
题目:1297. 子串的最大出现次数
> Problem: 1297. 子串的最大出现次数 题目:1297. 子串的最大出现次数 题目描述 给定一个字符串 s,要求找到满足以下条件的任意子串的出现次数,并返回该子串的最大出现次数: 子串中不同字母的数目必须小于等于 maxLetters。…...
一力破万法,高并发系统优化通解思路
高并发系统优化:从理论到Java实践 针对高并发场景,以下策略能够有效提升系统的稳定性和响应速度: 加集群 结果:通过增加服务器数量,实现负载均衡,提高系统整体处理能力。过程: 配置负载均衡器&…...
P8635 [蓝桥杯 2016 省 AB] 四平方和
对于一个给定的正整数,可能存在多种平方和的表示法。 要求你对 44个数排序使得 0≤a≤b≤c≤d。 输入 #1复制 5 输出 #1 0 0 1 2 输入 #2 12 输出 #2 0 2 2 2 输入 #3 773535 输出 #3 1 1 267 838 代码 #include<bits/stdc.h> using namespace …...
ElasticSearch是什么?
1.概述 Elasticsearch 是一个基于 Apache Lucene 构建的开源分布式搜索引擎和分析引擎。它专为云计算环境设计,提供了一个分布式的、高可用的实时分析和搜索平台。Elasticsearch 可以处理大量数据,并且具备横向扩展能力,能够通过增加更多的硬…...
2024年四非边缘鼠鼠计算机保研回忆(记录版 碎碎念)
Hi,大家好,我是半亩花海。写下这篇博客时已然是金秋十月,心中的石头终于落地,恍惚间百感交集。对于保研这条路,我处于摸着石头过河、冲击、随缘的这些状态。计算机保研向来比其他专业难,今年形势更是艰难。…...
clickhouse常用脚本语句
1.创建库和删除库 drop database IF EXISTS rt_db CREATE DATABASE rt_db ENGINE = Ordinary; CREATE DATABASE rt_db ENGINE = Atomic;2.创建表 CREATE TABLE IF NOT EXISTS intellect_alarm_info ( `id` UInt64 , `client_info_id...
GeneMark软件的秘钥gm_key失效怎么办?
GeneMark软件的gm_key失效怎么办 1. 下载网址(为软件的下载界面):http://topaz.gatech.edu/GeneMark/license_download.cgi 2.下载界面 根据自己的需求下载对应的版本和类型的gm_key秘钥 3.填写注册信息 4. 点击下载软件和密钥 5. 将秘钥…...
线性回归逻辑回归-笔记
一、线性回归(Linear Regression) 1. 定义 线性回归是一种用于回归问题的算法,旨在找到输入特征与输出值之间的线性关系。它试图通过拟合一条直线来最小化预测值与真实值之间的误差。 2. 模型表示 线性回归模型假设目标变量(输…...
如何将数据从 AWS S3 导入到 Elastic Cloud - 第 1 部分:Elastic Serverless Forwarder
作者:来自 Elastic Hemendra Singh Lodhi 这是多部分博客系列的第一部分,探讨了将数据从 AWS S3 导入 Elastic Cloud 的不同选项。 Elasticsearch 提供了多种从 AWS S3 存储桶导入数据的选项,允许客户根据其特定需求和架构策略选择最合适的方…...
Linux基础-正则表达式
正则表达式概述 正则表达式是处理字符串的一种工具,可以用于查找、删除、替换特定的字符串,主要用于文件内容的处理。与之不同的是,通配符则用于文件名称的匹配。正则表达式通过使用特殊符号,帮助用户轻松实现对文本的操作。 一…...
【HTML格式PPT离线到本地浏览】
文章目录 概要实现细节小结 概要 最近在上课时总是出现网络不稳定导致的PPT无法浏览的情况出现,就想到下载到电脑上。但是PPT是一个HTML的网页,无法通过保存网页(右键另存为mhtml只能保存当前页)的形式全部下载下来,试…...
如何在Vue项目中封装axios
文章目录 一、axios简介基本使用 二、封装axios的原因三、封装axios的方法1. 设置接口请求前缀2. 设置请求头和超时时间3. 封装请求方法4. 添加请求拦截器5. 添加响应拦截器小结 一、axios简介 axios 是一个基于 XMLHttpRequest 的轻量级HTTP客户端,适用于浏览器和…...
linux 配置ssh免密登录
一、 cd /root/.ssh/ #不存在就创建mkdir /root/.ssh ssh-keygen #连续按4个回车 ll二、将公钥发送到目标服务器下 #公钥上传到目标服务器 ssh-copy-id root192.168.31.142 #回车完也是要输入密码的 #测试一下免密登录: ssh root192.168.31.142 成功...
【AI绘画】Midjourney进阶:三分线构图详解
博客主页: [小ᶻZ࿆] 本文专栏: AI绘画 | Midjourney 文章目录 💯前言💯什么是构图为什么Midjourney要使用构图 💯三分线构图特点使用场景提示词书写技巧测试 💯小结 💯前言 【AI绘画】Midjourney进阶&a…...
享元模式(C++)
定义:享元模式是一种结构型设计模式,它使用共享对象,用以尽可能减少内存使用和提高性能。享元模式通过共享已经存在的对象实例,而不是每次需要时都创建新对象实例,从而避免大量重复对象的开销。 对比: 与单…...
开发一个UniApp需要多长时间
开发一个UniApp所需的时间因项目的规模、复杂度、开发团队的经验水平以及开发过程中的需求变更等多种因素而异。因此,很难给出一个确切的时间范围。然而,我们可以从以下几个方面来大致估算开发时间: 项目规划与需求分析: 在项目开…...
2026年主流抓娃娃App大对比,哪个才是你的“抓宝神器”?
在当今快节奏的生活中,年轻人面临着来自学业、工作、社交等多方面的压力。为了缓解这些压力,寻找适合的解压方式成为了大家的共同需求。抓娃娃App作为一种新兴的娱乐方式,正逐渐受到年轻人的喜爱。下面我们就从潮流趋势、科技前沿、行业洞察等…...
【低功耗蓝牙】④ 蓝牙MIDI协议:从ESP32 MicroPython代码到智能乐器DIY
1. 蓝牙MIDI协议入门:从音乐小白到智能乐器开发者 第一次听说蓝牙MIDI协议时,我正盯着桌上的ESP32开发板发呆。作为一个只会弹几个和弦的编程爱好者,完全没想到自己能用代码"演奏"音乐。蓝牙MIDI就像音乐世界的通用语言,…...
NS-USBLoader终极指南:3步搞定Switch游戏管理与RCM注入的完整教程
NS-USBLoader终极指南:3步搞定Switch游戏管理与RCM注入的完整教程 【免费下载链接】ns-usbloader Awoo Installer and GoldLeaf uploader of the NSPs (and other files), RCM payload injector, application for split/merge files. 项目地址: https://gitcode.c…...
Sketchfab数据提取终极指南:打破在线3D模型下载壁垒的完整解决方案
Sketchfab数据提取终极指南:打破在线3D模型下载壁垒的完整解决方案 【免费下载链接】sketchfab sketchfab download userscipt for Tampermonkey by firefox only 项目地址: https://gitcode.com/gh_mirrors/sk/sketchfab 你是否曾在Sketchfab上发现完美的3D…...
Windows Cleaner终极指南:3步彻底解决C盘爆红问题,让电脑重获新生!
Windows Cleaner终极指南:3步彻底解决C盘爆红问题,让电脑重获新生! 【免费下载链接】WindowsCleaner Windows Cleaner——专治C盘爆红及各种不服! 项目地址: https://gitcode.com/gh_mirrors/wi/WindowsCleaner 还在为Wind…...
量化交易强化学习环境TradingGym:从Gym接口到实战策略训练
1. 项目概述:一个为量化交易策略量身定制的强化学习训练场如果你正在尝试将强化学习(Reinforcement Learning, RL)应用到股票、期货或加密货币的量化交易中,大概率会遇到一个共同的困境:环境太难搭了。市面上的回测框架…...
轻量级HTTP代理monica-proxy:精准流量转发与多场景部署指南
1. 项目概述与核心价值最近在折腾一些需要跨网络环境访问特定服务的项目,发现一个挺有意思的工具叫ycvk/monica-proxy。这本质上是一个基于 Go 语言开发的轻量级 HTTP/HTTPS 代理服务器,但它和我们常见的那些“全能型”代理不太一样。它的设计初衷非常聚…...
VS Code光标主题定制指南:提升开发效率与视觉舒适度
1. 项目概述:一个为开发者量身定制的光标主题集合如果你和我一样,每天有超过8个小时的时间是在代码编辑器里度过的,那么你一定对那个在屏幕上闪烁的光标再熟悉不过了。它不仅仅是文本插入点,更是我们思维在数字世界中的延伸。然而…...
别再手动调色了!用Matlab bar3函数一键生成论文级渐变三维柱状图(附完整代码)
别再手动调色了!用Matlab bar3函数一键生成论文级渐变三维柱状图(附完整代码) 科研图表的美观程度直接影响论文的第一印象,而三维柱状图在展示多维度数据时尤为常见。传统手动调整每个柱体的颜色、透明度、光照效果不仅耗时&#…...
未来之窗昭和仙君(九十三)用户指引自助教学源码—东方仙盟
代码<!DOCTYPE html> <html lang"zh-CN"> <head> <meta charset"UTF-8"> <meta http-equiv"X-UA-Compatible" content"IEedge,chrome1"> <title>你的导师-未来之窗</title> <style>*…...
