TypeScript 学习笔记 — 模板字符串和类型体操(十五)
Posted Echoyya、
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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:$sizepx;`;
- 在映射类型中使用模板字符串
对象属性重命名
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>;
Swift学习笔记-对象和类
类
定义
通过class
关键词定义类。
在类里边声明属性
与声明常量
或者变量
的方法是相同的,唯一的区别的它们在类环境
下。
同样的, -方法
和函数
-(方法和函数不是一回事吗?) 的声明也是相同的写法。
class Shape
var numberOfSides = 0
func simpleDescription() -> String
return “A shape with \\(numberOfSides) sides.”
实例化
在类名后用()
来创建类的实例。
使用点语法
来访问实例的属性和方法。
var shape = Shape()
shape.numberOfSides = 7
var shapeDescription = shape.simpleDescription()
构造函数:init
使用init
来创建一个构造函数。
class NamedShape
var numberOfSides: Int = 0
var name: String
init(name: String)
self.name = name
func simpleDescription() -> String
return “A shape with \\(numberOfSides) sides.”
注意:
使用self
来区分name是类属性
还是构造函数的参数
。
析构函数:deinit
使用 deinit
来创建一个析构函数
,可以用来在释放对象之前执行一些清理工作。
子类和override关键字
在类名后用:
跟上父类的名字来定义子类。
class Square: NamedShape
子类的方法如果要重写父类的实现,则需要使用 override
——不使用 override关键字来标记则会导致编译器报错。
override func simpleDescription() -> String
return “A square with sides of length \\(sideLength).”
存储属性和计算属性
带有getter和setter的计算属性:
var perimeter: Double
get
return 3.0 * sideLength
set
sideLength = newValue / 3.0
在 perimeter的 setter 中,新值被隐式地命名为 newValue
。你可以提供一个显式
的名字放在 set 后边的圆括号里。
set(newValue: Double)
sideLength = newValue / 3.0
willSet与didSet
如果你不需要计算属性
但仍然需要在设置一个新值的前后执行代码,使用 willSet
和 didSet
。
var triangle: EquilateralTriangle
willSet
square.sideLength = newValue.sideLength
var square: Square
willSet
triangle.sideLength = newValue.sideLength
?的使用
你可以在可选项
前边使用 ?
,比如方法
,属性
和下标脚本
。
如果 ?
前的值是 nil
,那 ?
后的所有内容都会被忽略
并且整个表达式的值都是 nil
。
否则,可选项的值将被展开
,然后 ?
后边的代码根据展开的值执行。
在这两种情况当中,表达式的值是一个可选
的值。
let optionalSquare: Square? = Square(sideLength: 2.5, name: “optional square”)
let sideLength = optionalSquare?.sideLength
Swift学习群
欢迎加入本人的Swift学习微信群,一同互相监督学习,我微信:reese90
以上是关于TypeScript 学习笔记 — 模板字符串和类型体操(十五)的主要内容,如果未能解决你的问题,请参考以下文章
TypeScript学习笔记——TS类型/高级用法及实战优缺点
TypeScript学习笔记——TS类型/高级用法及实战优缺点
C++学习笔记:高级编程:模板,预处理器,信号处理,多线程,Web编程