首页 > 其他分享 >TypeScript 学习笔记 — 模板字符串和类型体操(十五)

TypeScript 学习笔记 — 模板字符串和类型体操(十五)

时间:2023-05-04 15:34:42浏览次数:37  
标签:TypeScript 类型 extends 体操 字符串 type infer 模板

目录

基本介绍

TS 中模板字符串类型 与 JS 模板字符串非常类似,,通过 ${} 包裹,

  1. 模板字符串类型的目的就是将多个字符串组装在一起
type name = "Echoyya";
type sayHaha = `hi ${name} haha`; // type name = "Echoyya";
  1. 模板字符串具备分发的机制可以组成联合类型
    实现:marign-left、 margin-top、 margin-bottom.....
type Direction = "left" | "right" | "top" | "bottom";
type size = "10" | "20";
type AllMargin = `margin-${Direction}:${size}px;`;
  1. 在映射类型中使用模板字符串

对象属性重命名

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,类型,extends,体操,字符串,type,infer,模板
From: https://www.cnblogs.com/echoyya/p/17347552.html

相关文章

  • typescript基本语法
    TypeScript是JavaScript的一个超集,为JavaScript添加了类型、接口、泛型、类、模块等新的特性。以下是TypeScript一些基本语法:变量声明在TypeScript中使用let、const、var关键字来声明变量,使用冒号+类型来指定变量的类型,例如:letcount:number=10;constname:string='Tom'......
  • TypeScript 面试题
    一、TypeScript是什么?JavaScript是一种解释型的脚本语言,基于对象,跨平台的特性,活跃于各大网站制作中。而TypeScript则是以JavaScript作为基础,并对其扩展的一种新的语言, 二、TypeScript的内置数据类型有哪些?数字类型:用于表示数字类型的值。TypeScript中的所有数字都存储为浮......
  • TypeScript 基础语法以及注意事项
    TypeScript(简称TS)是一种由Microsoft开发的静态类型检查器,它在JavaScript的基础上添加了强类型和其他一些特性。以下是TS的一些基本语法和注意事项:变量声明 在TS中,变量声明时需要指定其类型,例如:这样就声明了一个名为myString的字符串变量,并将其赋值为"Hello,TypeScript!"......
  • 1159 Structure of a Binary Tree + 根据前序和中序构建二叉树+ 层序遍历模板复习
    题目链接:https://pintia.cn/problem-sets/994805342720868352/exam/problems/1478635126488367104唉,今天的bug出在了下面这条语句。if(tree[root_key].left*tree[root_key].right<0)full_tree=false;我写成了full_tree=!(tree[root_key].left*tree[root_key].rig......
  • 根据PDF模板生成具体内容PDF,模板pdf需要设置字段域
    packagecom.zudp.common.core.utils.pdf;importcom.itextpdf.text.DocumentException;importcom.itextpdf.text.Image;importcom.itextpdf.text.Rectangle;importcom.itextpdf.text.pdf.*;importorg.apache.commons.lang3.StringUtils;importorg.apache.http.en......
  • 「模板」前缀和
    阿巴阿巴阿巴输入n个数,给出m个询问,询问区间[x,y]的和。输入第一行为n和m,1<=n,m<=100000接下来一行为n个数,范围在0~100000之间接下来m行,每行两个数x,y,输出第x个数到第y个数之间所有数的和。保证x<=y输出m个数tips:1#include<bits/stdc++.h>2usingnamespacestd;3......
  • 扫描线【模板】
    扫描线用离散线段树实现时间复杂度\(O(n\logn)\)P5490【模板】扫描线题目描述代码#include<bits/stdc++.h>usingnamespacestd;#definemid(l+r)/2#definelsonl,mid,rt<<1#definersonmid,r,rt<<1|1#defineintlonglongconstintmaxn=2e5+10;intn,y[ma......
  • django模板语法
    django模板语法代码{%loadstatic%}<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>Title</title>{#<linkrel="stylesheet"href="/static/plugins/b......
  • typescript重写canvas --7.利用clip在指定区域绘图
    typescript重写canvas--7.利用clip在指定区域绘图1.使用canvas利用clip在指定区域绘图<!DOCTYPEHTML><html><head><metacharset="utf-8"/></head><body><canvasid="myCanvas"width="250"height="200......
  • 【模板】快读快写
    快读inlineintread(){ intx=0;boolf=1;chars=getchar(); while(s<'0'||s>'9'){if(s=='-')f=0;s=getchar();} while(s>='0'&&s<='9'){x=(x<<1)+(x<<3)+(s^48);s=getchar();} retur......