TypeScript 学习笔记 — 模板字符串和类型体操(十五)
- 基本介绍
- 字符串类型体操实操环节
- 1. 字符串首字母大写 CapitalizeString
- 2. 获取字符串第一个字符 FirstChar
- 3. 获取字符串最后一个字符 LastChar
- 4. 字符串转元组 StringToTuple
- 5. 元组转字符串 TupleToString
- 6. 重复字符串 RepeatString
- 7. 字符串分割 SplitString
- 8. 获取字符串长度 LengthOfString
- 9. 驼峰转为短横线隔开式 KebabCase
- 10. 短横线隔开式转为驼峰 CamelCase
- 11. 字符串是否包含某个字符 Include
- 12. 去掉左右空格 Trim
- 13. 字符串替换 Replace
- 14. 函数重命名改变返回值类型 ComponentEmitsType
基本介绍
TS 中模板字符串类型 与 JS 模板字符串非常类似,,通过 ${}
包裹,
- 模板字符串类型的目的就是将多个字符串组装在一起
type name = "Echoyya";
type sayHaha = `hi ${name} haha`; // type name = "Echoyya";
- 模板字符串具备分发的机制可以组成联合类型
实现:marign-left、 margin-top、 margin-bottom.....
type Direction = "left" | "right" | "top" | "bottom";
type size = "10" | "20";
type AllMargin = `margin-${Direction}:${size}px;`;
- 在映射类型中使用模板字符串
对象属性重命名
type Person = { name: string; age: number; address: string };
// 全部重命名
type RenamePerson<T> = {
[K in keyof T as `rename_${K & string}`]: T[K];
};
// 仅为指定的key重命名
type RenamePersonForKey<T, X extends keyof T> = {
[K in keyof T as K extends X ? `rename_${K & string}` : K]: T[K];
};
type a1 = RenamePerson<Person>; // rename_name, rename_age, rename_address
type a2 = RenamePersonForKey<Person, "name">; // rename_name,age,address
针对模板字符串内部还提供了很多专门的类型,可以供我们使用 Uppercase 转大写
、Lowercase转小写
、Capitalize首字母大写
、Uncaptailize首字母小写
使用模板字符串和内置的类型,实现为对象类型统一生成对象属性的 getter / setter 等方法
type Person = { name: string; age: number; address: string };
type PersonGetter<T> = {
[K in keyof T as `get${Capitalize<K & string>}`]: () => T[K];
};
let person!: PersonGetter<Person>;
person.getName();
person.getAge();
person.getAddress();
Emits 方法的封装
实现:{ onA: () => {}; onB: () => {}; onC: () => {} }
type Events = { a: () => {}; b: () => {}; c: () => {} };
type EmitsGetter<T> = {
[K in keyof T as `on${Capitalize<K & string>}`]: T[K];
};
type EmitsEvents = EmitsGetter<Events>;
模板字符串配合 infer 使用
和元组的 infer 用法很相似 [infer L,...infer R]
,L 是第一个,又有点像正则的匹配模式
type getFirstWord<S extends string> = S extends `${infer L} ${string}` ? L : any;
type FirstWord = getFirstWord<"hello world">; // type FirstWord = "hello"
字符串类型体操实操环节
TS 通过 type 声明的类型,如果设置了泛型,也就是类型参数,就是高级类型。高级类型的目的是通过一系列类型运算来生成更准确的类型。这种生成不同类型的高级类型的生成逻辑,就是所谓的类型体操
。
1. 字符串首字母大写 CapitalizeString
export type CapitalizeString<T> = T extends string ? `${Capitalize<T>}` : T;
type a1 = CapitalizeString<"handler">; // Handler
type a2 = CapitalizeString<"echoyya">; // Echoyya
type a3 = CapitalizeString<233>; // 233
2. 获取字符串第一个字符 FirstChar
export type FirstChar<T> = T extends `${infer L}${infer R}` ? L : never;
type A = FirstChar<"BFE">; // 'B'
type B = FirstChar<"Echoyya">; // 'd'
type C = FirstChar<"">; // never
3. 获取字符串最后一个字符 LastChar
export type LastChar<T, F extends string = ""> = T extends `${infer L}${infer R}` ? LastChar<R, L> : F;
type A = LastChar<"BFE">; // E
type B = LastChar<"Echoyya">; // a
type C = LastChar<"a">; // a
4. 字符串转元组 StringToTuple
export type StringToTuple<T, F extends any[] = []> = T extends `${infer L}${infer R}` ? StringToTuple<R, [...F, L]> : F;
type A = StringToTuple<"Echoyya">; // ["E", "c", "h", "o", "y", "y", "a"]
type B = StringToTuple<"">; // []
5. 元组转字符串 TupleToString
export type TupleToString<T, F extends string = ""> = T extends [infer L, ...infer R]
? TupleToString<R, `${F}${L & string}`> // 模板字符串拼接
: F;
type A = TupleToString<["E", "c", "h", "o"]>; // Echo
type B = TupleToString<["a"]>; // a
type C = TupleToString<[]>; // ''
6. 重复字符串 RepeatString
export type RepeatString<
T extends string,
C, // 重复次数
A extends any[] = [], // 拼接Arr
F extends string = "" // 最终结果
> = C extends A["length"] // Arr长度是否满足重复C
? F
: RepeatString<T, C, [...A, null], `${F}${T}`>;
type A = RepeatString<"a", 3>; // 'aaa'
type B = RepeatString<"a", 0>; // ''
7. 字符串分割 SplitString
type SplitString<
T extends string,
S extends string, // 分割符
F extends any[] = [] // 最终结果
> = T extends `${infer L}${S}${infer R}` // infer 匹配模式
? SplitString<R, S, [...F, L]>
: [...F, T]; // 最后一次不满足条件时,需要将最后一个单词也放入结果集中
type A1 = SplitString<"handle-open-flag", "-">; // ["handle", "open", "flag"]
type A2 = SplitString<"flag", "-">; // ["flag"]
type A3 = SplitString<"handle.open.flag", ".">; // ["handle", "open", "flag"]
type A4 = SplitString<"open.flag", "-">; // ["open.flag"]
8. 获取字符串长度 LengthOfString
type LengthOfString<T extends string, F extends any[] = []> = T extends `${infer L}${infer R}` ? LengthOfString<R, [...F, L]> : F["length"];
type A = LengthOfString<"Echoyya">; // 7
type B = LengthOfString<"">; // 0
9. 驼峰转为短横线隔开式 KebabCase
type KebabCase<T extends string, F extends string = ""> = T extends `${infer L}${infer R}`
? KebabCase<R, `${F}${Capitalize<L> extends L ? `-${Lowercase<L>}` : L}`> // 取每个字母判断 是否与其大写一致,拼接短横线并转为小写
: RemoveFirst<F>; // 当第一个字母也是大写时会多一个-,需要截取调
type RemoveFirst<T extends string> = T extends `${infer L}${infer R}` ? R : T;
type a1 = KebabCase<"HandleOpenFlag">; // handle-open-flag
type a2 = KebabCase<"EchoYya">; // echo-yya
10. 短横线隔开式转为驼峰 CamelCase
type CamelCase<T extends string, F extends string = ""> = T extends `${infer L}-${infer R1}${infer R2}`
? CamelCase<R2, `${F}${L}${Capitalize<R1>}`> // 递归R2,去掉-,拼接大写的R1
: Capitalize<`${F}${T}`>; // 结果首字母也需要大写
type a1 = CamelCase<"handle-open-flag">; // HandleOpenFlag
type a2 = CamelCase<"echo-yya">; // EchoYya
11. 字符串是否包含某个字符 Include
type Include<T extends string, C extends string> = T extends ""
? C extends ""
? true
: false // 空字符串时需要特殊处理
: T extends `${infer L}${C}${infer R}`
? true
: false;
type a1 = Include<"Echoyya", "E">; // true
type a2 = Include<"Echoyya", "o">; // true
type a3 = Include<"", "">; // true 空字符串时需要特殊处理
type a4 = Include<"", "a">;
12. 去掉左右空格 Trim
type TrimLeft<T extends string> = T extends ` ${infer R}` ? TrimLeft<R> : T;
type TrimRight<T extends string> = T extends `${infer L} ` ? TrimRight<L> : T;
type Trim<T extends string> = TrimLeft<TrimRight<T>>;
type a1 = Trim<" Echoyya ">; // Echoyya
13. 字符串替换 Replace
type Replace<T extends string, C extends string, RC extends string, F extends string = ""> =
// 空格替换 特殊处理
C extends ""
? T extends ""
? RC
: `${RC}${T}`
: T extends `${infer L}${C}${infer R}` // 匹配模式
? Replace<R, C, RC, `${F}${L}${RC}`> // 结果拼接并替换
: `${F}${T}`;
type a1 = Replace<"ha ha ha 123", "ha", "he">; // he he he 123
type a2 = Replace<"Ey", "Ey", "Echoyya">; //Echoyya
type a4 = Replace<"", "", "Echo">; //Echo
type a3 = Replace<"a", "", "yya">; //yyaa
14. 函数重命名改变返回值类型 ComponentEmitsType
// 转化为
/*
{
onHandleOpen?: (flag: boolean) => void,
onPreviewItem?: (data: { item: any, index: number }) => void,
onCloseItem?: (data: { item: any, index: number }) => void,
}
*/
type a1 = {
"handle-open": (flag: boolean) => true;
"preview-item": (data: { item: any; index: number }) => true;
"close-item": (data: { item: any; index: number }) => true;
};
type CamelCase<T extends string, F extends string = ""> = T extends `${infer L}-${infer R1}${infer R2}`
? CamelCase<R2, `${F}${L}${Capitalize<R1>}`> // 递归R2,去掉-,拼接大写的R1
: Capitalize<`${F}${T}`>; // 结果首字母也需要大写
type ComponentEmitsType<T> = {
[K in keyof T as `on${CamelCase<K & string>}`]: T[K] extends (...args: infer P) => any // 参数类型不变
? (...args: P) => void // 仅改变返回值类型
: T[K];
};
type a2 = ComponentEmitsType<a1>;
TypeScript 学习笔记 — 模板字符串和类型体操(十五)的更多相关文章
- es6学习笔记--模板字符串
这几天简单看了一下深入浅出es6这本书,感觉特实用,学习了一个新特性---模板字符串在项目开发中,拼接字符串是不可缺少的,动态创建dom元素以及js操作数据都要拼接字符串,在es6出来之前,我们都通常 ...
- TypeScript 学习笔记 — 函数中的类型(四)
目录 函数的两种声明方式 可选参数 默认参数 剩余参数 函数的重载 this 的类型 对于函数主要关心的是:函数的入参类型 和 函数的返回值类型 函数的两种声明方式 通过 function 关键字来进 ...
- Typescript 学习笔记七:泛型
中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...
- Typescript 学习笔记六:接口
中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...
- Typescript 学习笔记二:数据类型
中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...
- javascript学习笔记(四) Number 数字类型
数字格式化方法toFixed().toExponential().toPrecision(),三个方法都四舍五入 toFixed() 方法指定小数位个数 toExponential() 方法 用科学 ...
- Typescript 学习笔记五:类
中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...
- Typescript 学习笔记三:函数
中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...
- Typescript 学习笔记一:介绍、安装、编译
前言 整理了一下 Typescript 的学习笔记,方便后期遗忘某个知识点的时候,快速回忆. 为了避免凌乱,用 gitbook 结合 marketdown 整理的. github地址是:ts-gitb ...
- 【学习笔记】字符串—马拉车(Manacher)
[学习笔记]字符串-马拉车(Manacher) 一:[前言] 马拉车用于求解连续回文子串问题,效率极高. 其核心思想与 \(kmp\) 类似:继承. --引自 \(yyx\) 学姐 二:[算法原理] ...
随机推荐
- mongodb的备份与恢复详解
简单 Mongodb导出与导入 1: 导入/导出可以操作的是本地的mongodb服务器,也可以是远程的.所以,都有如下通用选项:-h host 主机--port port 端口-u username ...
- supersocket实际应用之你画我猜游戏(一)
supersocket这款组件,让不懂tcp/ip的人都能开发出网络应用.我们不必在开发与自己主要应用不相关的代码了,主要精力都能放在设计业务逻辑上面了. 现在使用现成又完备的组件,真是大大的提高了开 ...
- ClickHouse 初步认识
概述 Clickhouse 是分析型数据库,真正的面向列式存储,支持高维度表.它免费开源.具备高效的数据导入和查询性能,能达到 50M/200M 每秒.支持实时查询.支持不同功能底层存储引擎,例如:M ...
- go 通过指针修改结构体小写字段的值
package main import ( "fmt" "unsafe" ) type W struct { b int32 c int64 } func ma ...
- K8S POD控制器:从基础到高级实战技巧
本文深入探讨了Kubernetes POD控制器的基础知识.配置示例.最佳实践,并通过一个电子商务公司的案例分析,展示了如何在复杂的生产环境中应用POD控制器,以优化云服务架构. 关注[TechLea ...
- docker lnmp
#wiki: https://github.com/2233466866/lnmp/wiki #安装docker wget -O /etc/yum.repos.d/ali_docker-ce.repo ...
- Leetcode-916. Word Subsets-(Medium)
一.问题描述 We are given two arrays A and B of words. Each word is a string of lowercase letters. Now, s ...
- 面试必问:MySQL死锁 是什么,如何解决?(史上最全)
MySQL死锁接触少,但面试又经常被问到怎么办? 最近有小伙伴在面试的时候,被问了MySQL死锁,如何解决? 虽然也回答出来了,但是不够全面体系化, 所以,小北给大家做一下系统化.体系化的梳理,帮助大 ...
- 7.12考试总结(NOIP模拟12)[简单的区间·简单的玄学·简单的填数]
即使想放弃,也没法放弃最想要的东西,这就是人 前言 这次应该是和 SDFZ 一起打的第一场比赛吧. 然而我还是 FW 一个... 这次考试也有不少遗憾,主要的问题是码力不足,不敢去直面正解,思考程度不 ...
- c# IdHelper生成唯一的雪花Id
为什么使用雪花ID 在以前的项目中,最常见的两种主键类型是自增Id和UUID,在比较这两种ID之前首先要搞明白一个问题,就是为什么主键有序比无序查询效率要快,因为自增Id和UUID之间最大的不同点就在 ...