天天微动态丨TypeScript 学习笔记 — 模板字符串和类型体操(十五)
基本介绍TS中模板字符串类型与JS模板字符串非常类似,,通过${}包裹,模板字符串类型的目的就是将多个字符串
2023-05-04(相关资料图)
目录TS 中模板字符串类型 与 JS 模板字符串非常类似,,通过 ${}
包裹,
type name = "Echoyya";type sayHaha = `hi ${name} haha`; // type name = "Echoyya";
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 = { [K in keyof T as `rename_${K & string}`]: T[K];};// 仅为指定的key重命名type RenamePersonForKey = { [K in keyof T as K extends X ? `rename_${K & string}` : K]: T[K];};type a1 = RenamePerson; // rename_name, rename_age, rename_addresstype a2 = RenamePersonForKey; // rename_name,age,address
针对模板字符串内部还提供了很多专门的类型,可以供我们使用 Uppercase 转大写
、Lowercase转小写
、Capitalize首字母大写
、Uncaptailize首字母小写
使用模板字符串和内置的类型,实现为对象类型统一生成对象属性的 getter / setter 等方法
type Person = { name: string; age: number; address: string };type PersonGetter = { [K in keyof T as `get${Capitalize}`]: () => T[K];};let person!: PersonGetter;person.getName();person.getAge();person.getAddress();
Emits 方法的封装实现:{ onA: () => {}; onB: () => {}; onC: () => {} }
type Events = { a: () => {}; b: () => {}; c: () => {} };type EmitsGetter = { [K in keyof T as `on${Capitalize}`]: T[K];};type EmitsEvents = EmitsGetter;
模板字符串配合 infer 使用和元组的 infer 用法很相似 [infer L,...infer R]
,L 是第一个,又有点像正则的匹配模式
type getFirstWord = S extends `${infer L} ${string}` ? L : any;type FirstWord = getFirstWord<"hello world">; // type FirstWord = "hello"
TS 通过 type 声明的类型,如果设置了泛型,也就是类型参数,就是高级类型。高级类型的目的是通过一系列类型运算来生成更准确的类型。这种生成不同类型的高级类型的生成逻辑,就是所谓的类型体操
。
export type CapitalizeString = T extends string ? `${Capitalize}` : T;type a1 = CapitalizeString<"handler">; // Handlertype a2 = CapitalizeString<"echoyya">; // Echoyyatype a3 = CapitalizeString<233>; // 233
export type FirstChar = T extends `${infer L}${infer R}` ? L : never;type A = FirstChar<"BFE">; // "B"type B = FirstChar<"Echoyya">; // "d"type C = FirstChar<"">; // never
export type LastChar = T extends `${infer L}${infer R}` ? LastChar : F;type A = LastChar<"BFE">; // Etype B = LastChar<"Echoyya">; // atype C = LastChar<"a">; // a
export type StringToTuple = T extends `${infer L}${infer R}` ? StringToTuple : F;type A = StringToTuple<"Echoyya">; // ["E", "c", "h", "o", "y", "y", "a"]type B = StringToTuple<"">; // []
export type TupleToString = T extends [infer L, ...infer R] ? TupleToString // 模板字符串拼接 : F;type A = TupleToString<["E", "c", "h", "o"]>; // Echotype B = TupleToString<["a"]>; // atype C = TupleToString<[]>; // ""
export type RepeatString< T extends string, C, // 重复次数 A extends any[] = [], // 拼接Arr F extends string = "" // 最终结果> = C extends A["length"] // Arr长度是否满足重复C ? F : RepeatString;type A = RepeatString<"a", 3>; // "aaa"type B = RepeatString<"a", 0>; // ""
type SplitString< T extends string, S extends string, // 分割符 F extends any[] = [] // 最终结果> = T extends `${infer L}${S}${infer R}` // infer 匹配模式 ? SplitString : [...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"]
type LengthOfString = T extends `${infer L}${infer R}` ? LengthOfString : F["length"];type A = LengthOfString<"Echoyya">; // 7type B = LengthOfString<"">; // 0
type KebabCase = T extends `${infer L}${infer R}` ? KebabCase extends L ? `-${Lowercase}` : L}`> // 取每个字母判断 是否与其大写一致,拼接短横线并转为小写 : RemoveFirst; // 当第一个字母也是大写时会多一个-,需要截取调type RemoveFirst = T extends `${infer L}${infer R}` ? R : T;type a1 = KebabCase<"HandleOpenFlag">; // handle-open-flagtype a2 = KebabCase<"EchoYya">; // echo-yya
type CamelCase = T extends `${infer L}-${infer R1}${infer R2}` ? CamelCase}`> // 递归R2,去掉-,拼接大写的R1 : Capitalize<`${F}${T}`>; // 结果首字母也需要大写type a1 = CamelCase<"handle-open-flag">; // HandleOpenFlagtype a2 = CamelCase<"echo-yya">; // EchoYya
type Include = T extends "" ? C extends "" ? true : false // 空字符串时需要特殊处理 : T extends `${infer L}${C}${infer R}` ? true : false;type a1 = Include<"Echoyya", "E">; // truetype a2 = Include<"Echoyya", "o">; // truetype a3 = Include<"", "">; // true 空字符串时需要特殊处理type a4 = Include<"", "a">;
type TrimLeft = T extends ` ${infer R}` ? TrimLeft : T;type TrimRight = T extends `${infer L} ` ? TrimRight : T;type Trim = TrimLeft>;type a1 = Trim<" Echoyya ">; // Echoyya
type Replace = // 空格替换 特殊处理 C extends "" ? T extends "" ? RC : `${RC}${T}` : T extends `${infer L}${C}${infer R}` // 匹配模式 ? Replace // 结果拼接并替换 : `${F}${T}`;type a1 = Replace<"ha ha ha 123", "ha", "he">; // he he he 123type a2 = Replace<"Ey", "Ey", "Echoyya">; //Echoyyatype a4 = Replace<"", "", "Echo">; //Echotype a3 = Replace<"a", "", "yya">; //yyaa
// 转化为/* { 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 `${infer L}-${infer R1}${infer R2}` ? CamelCase}`> // 递归R2,去掉-,拼接大写的R1 : Capitalize<`${F}${T}`>; // 结果首字母也需要大写type ComponentEmitsType = { [K in keyof T as `on${CamelCase}`]: T[K] extends (...args: infer P) => any // 参数类型不变 ? (...args: P) => void // 仅改变返回值类型 : T[K];};type a2 = ComponentEmitsType;