首页 > 其他分享 >TypeScript 学习笔记 — 数组常见的类型转换操作记录(十四)

TypeScript 学习笔记 — 数组常见的类型转换操作记录(十四)

时间:2023-04-24 16:14:56浏览次数:47  
标签:类型转换 ... TypeScript never 笔记 extends Fail type infer

  1. 获取长度 length
type LengthOfTuple<T extends any[]> = T["length"];
type A = LengthOfTuple<["B", "F", "E"]>; // 3
type B = LengthOfTuple<[]>; // 0
  1. 取第一项 FirstItem
type FirstItem<T extends any[]> = T[0];
type A = FirstItem<[string, number, boolean]>; // string
type B = FirstItem<["B", "F", "E"]>; // 'B'
  1. 取最后一项 LastItem
type LastItem<T extends any[]> = T extends [...any, infer R] ? R : never;
type A = LastItem<[string, number, boolean]>; // boolean
type B = LastItem<["B", "F", "E"]>; // 'E'
type C = LastItem<[]>; // never
  1. 删除第一项 shift
type Shift<T extends any[]> = T extends [infer L, ...infer R] ? R : T;

type A = Shift<[1, 2, 3]>; // [2,3] . [never,2,3]
type B = Shift<[1]>; // []
type C = Shift<[]>; // []
  1. 向后追加 Push
type Push<T extends any[], K> = [...T, K];

type A = Push<[1, 2, 3], 4>; // [1,2,3,4]
type B = Push<[1], 2>; // [1, 2]
  1. 翻转 ReverseTuple

通过递归完成,先声明一个F默认结果集,每次递归时,在将L第一个值添加在F展开之前,递归结束返回F

type ReverseTuple<T extends any[], F extends any[] = []> = T extends [infer L, ...infer R] ? ReverseTuple<R, [L, ...F]> : F;

type A = ReverseTuple<[string, number, boolean]>; // [boolean, number, string]
type B = ReverseTuple<[1, 2, 3]>; // [3,2,1]
type C = ReverseTuple<[]>; // []
  1. 拍平 Flat

通过递归完成,一个一个判断是否是数组,是数组继续 Flat,反之返回

type Flat<T extends any[], F extends any[] = []> = T extends [infer L, ...infer R]
  ? [...(L extends any[] ? Flat<L> : [L]), ...Flat<R>] // 判断第一个是否是数组
  : [];

type A = Flat<[1, 2, 3]>; // [1,2,3]
type B = Flat<[[[[[[[1]]]]]], [2, 3], [4, [5, [6]]]]>; // [1,2,3,4,5,6]
type C = Flat<[]>; // []
type D = Flat<[1]>; // [1]
  1. 复制 Repeat

在 ts 中操作与数量相关的,全部采用元素的长度来计算

C`表示需要的长度,`F`是最终结果,`F["length"]`,结果的长度,两者都是字面量类型,只有相等的时候才能 extends,满足条件返回 F,不满足接着 Repeat,再次递归时,需要将上次的`F`展开放进去,再放入原始数据`T
type Repeat<T, C, F extends any[] = []> = C extends F["length"] ? F : Repeat<T, C, [...F, T]>;

type A = Repeat<number, 3>; // [number, number, number]
type B = Repeat<string, 2>; // [string, string]
type C = Repeat<1, 1>; // [1]
type D = Repeat<0, 0>; // []
  1. 过滤 Filter
type Filter<T extends any[], I, F extends any[] = []> =
  // 先取出第一项,判断是否满足,满足递归处理R
  T extends [infer L, ...infer R]
    ? // 无论如何都要遍历剩余项, 所以在F这判断 是否要放到数组中,使用[]包裹是为了防止any分发返回联合类型
      Filter<R, A, [L] extends [A] ? [...F, L] : F>
    : F;
type A = Filter<[1, "BFE", 2, true, "dev"], number>; // [1, 2]
type B = Filter<[1, "BFE", 2, true, "dev"], string>; // ['BFE', 'dev']
type C = Filter<[1, "BFE", 2, any, "dev"], string>; // ["BFE", "dev"] | ["BFE", any, "dev"]
  1. 查找索引 FindIndex

实现思路:

  • 找到两个值相等的一项,思考如何判断两个值是否相等?
  • 最终要返回的是索引:内部构建一个数组,来记录当前遍历到了第几项
type errIsEqual<T, U, Success, Fail> = [T] extends [U] // 类型 + 结构
  ? [U] extends [T]
    ? Success
    : Fail
  : Fail;
type xx = errIsEqual<any, 1, true, false>; // 测试判等方法:返回了 true,但是 any != 1

// 因此由于any类型的特殊性, 需要判断两个类型是否相等。需要严格判断 两者的 类型 + 结构
type isEqual<T, U, Success, Fail> = [T] extends [U] // 类型 + 结构
  ? [U] extends [T]
    ? keyof T extends keyof U
      ? keyof U extends keyof T
        ? Success
        : Fail
      : Fail
    : Fail
  : Fail;

type yy = isEqual<any, 1, true, false>; // 测试判等方法:返回了 false

type FindIndex<T extends any[], I, F extends any[] = []> = T extends [infer L, ...infer R] 
  ? isEqual<L, I, F["length"], FindIndex<R, I, [...F, never]>> 
  : never;

type a1 = [any, never, 1, "2", true];
type a2 = FindIndex<a1, 1>; // 2
type a3 = FindIndex<a1, 3>; // never
  1. 元组转枚举 TupleToEnum
  • 默认情况下,枚举对象中的值就是元素中某个类型的字面量类型,
  • 第二个参数为 true,枚举对象中值的类型就是元素类型中某个元素在元组中的 index 索引,也就是数字字面量类型(需要借助上一个案例中 type FindIndex)
type isEqual<T, U, Success, Fail> = [T] extends [U] // 类型 + 结构
  ? [U] extends [T]
    ? keyof T extends keyof U
      ? keyof U extends keyof T
        ? Success
        : Fail
      : Fail
    : Fail
  : Fail;

type FindIndex<T extends any[], I, F extends any[] = []> = T extends [infer L, ...infer R] 
  ? isEqual<L, I, F["length"], FindIndex<R, I, [...F, never]>> 
  : never;
	
type TupleToEnum<T extends any[], I = false> = {
  readonly [K in T[number]]: I extends true ? FindIndex<T, K> : K;
};

// 默认情况下
type a1 = TupleToEnum<["MacOS", "Windows", "Linux"]>;
// { readonly MacOS: "MacOS", readonly Windows: "Windows", readonly Linux: "Linux" }

// 第二个参数为true
type a2 = TupleToEnum<["MacOS", "Windows", "Linux"], true>;
// { readonly MacOS: 0, readonly Windows: 1, readonly Linux: 2 }
  1. 截取 slice

实现思路:

  • 判断是否到达开始位置 S,到达就往结果集中添加,反之就舍弃
  • 判断是否到达结束位置 E,没到就往结果集中添加,反之就返回
type Slice<
  T extends any[],
  S extends number, // 开始位置
  E extends number = T["length"], // 结束位置
  SA extends any[] = [], // 用于记录是否到达 S
  EA extends any[] = [], // 用于记录是否到达 E
  F extends any[] = [] // 结果集
> = T extends [infer L, ...infer R]
  ? SA["length"] extends S // 判断是否满足 开始index,满足放入集合F中
    ? EA["length"] extends E // 判断是否满足 结束index,表示截取完成
      ? [...F, L] // 都满足,直接结束,返回结果集 + L
      : Slice<R, S, E, SA, [...EA, null], [...F, L]> // SA 匹配到索引就不在累积添加null
    : Slice<R, S, E, [...SA, null], [...EA, null], F> // 添加null 是为了占位,撑开数组长度
  : F;
type A1 = Slice<[any, never, 1, "2", true, boolean], 0, 2>; // [any,never,1]      ---0到2
type A2 = Slice<[any, never, 1, "2", true, boolean], 1, 3>; // [never,1,'2']      ---1到3
type A3 = Slice<[any, never, 1, "2", true, boolean], 1, 2>; // [never,1]          ---1到2
type A4 = Slice<[any, never, 1, "2", true, boolean], 2>; // [1,'2',true,boolean]  ---2到结束
type A5 = Slice<[any], 2>; // []                                                  ---2到结束
type A6 = Slice<[], 0>; // []
  1. 删除指定长度,并追加新的元素 splice

实现思路:

  • 判断是否到达开始位置 S,到达就往结果集中添加,反之就舍弃并且 SA++
  • 判断是否到达需要删除的个数,到达就拼接删除前的结果集 F + 需要添加的集合 I + 删除后剩下的集合,反之 DC++
type Splice<
  T extends any[],
  S extends number, // 开始index
  C extends number, // 需要删除的个数
  I extends any[] = [], // 需要插入的元素集合
  SA extends any[] = [], // 用于记录是否到达 S
  DC extends any[] = [], // 用于记录 已经删除的个数
  F extends any[] = [] // 结果集
> = T extends [infer L, ...infer R]
  ? SA["length"] extends S // 判断是否满足 开始index,满足放入集合F中
    ? DC["length"] extends C // 判断是否满足 要删除的长度
      ? [...F, ...I, ...T] // 都满足,返回F删除前的结果集 + 需要添加的集合 + 删除后剩下的集合
      : Splice<R, S, C, I, SA, [...DC, null], F> // 不满足删除的长度。DC++
    : Splice<R, S, C, I, [...SA, null], DC, [...F, L]> // 不满足开始index。SA++
  : F;

type A1 = Splice<[string, number, boolean, null, undefined, never], 0, 2>; // 从0开始删2个 [boolean,null,undefined,never]
type A2 = Splice<[string, number, boolean, null, undefined, never], 1, 3>; // 从1开始删3个 [string,undefined,never]
type A3 = Splice<[string, number, boolean, null, undefined, never], 1, 2, [1, 2, 3]>; // 从1开始删2个,添加另外3个 [string,1,2,3,null,undefined,never]

小总结

在 ts 中跟数量有关,全部会采用 length
凡是涉及遍历,全部采用递归[infer L,...infer R]来处理
['a','b','c'][number] 可以取到对应索引的 key 值
判断两个类型是否相等,需要考虑 any 类型,因此需要使用严格判等,类型 + 结构

标签:类型转换,...,TypeScript,never,笔记,extends,Fail,type,infer
From: https://www.cnblogs.com/echoyya/p/17274531.html

相关文章

  • 老杜Vue实战教程完整版笔记(一)Vue程序初体验
    Vue作为国内使用率最高,最火爆的前端框架学习这门技术也越来越重要~动力节点老杜最新版Vue2+3教程已经上线!还是原来的配方,还是熟悉的味道学习地址:https://www.bilibili.com/video/BV17h41137i4/1Vue程序初体验我们可以先不去了解Vue框架的发展历史、Vue框架有什么特点、Vu......
  • JAVA学习笔记随记1(类与对象)
    首先说明,这是为了学习java而做的笔记,所以记起来可能杂乱无章,无所谓了,刚开始学习都是这样的。。。首先小结下String的知识点String可以直接声明并赋初值并可以修改,例如:Stringabc="a";abc="b";其次字符串之间的连接用'+',只要出现字符串和其他数据类型之间用'+'连接,那么该......
  • VBA学习笔记
    2023-04-24(1)OptionExplicit:在模块最开始加这句代码,如果程序中有未声明的变量,程序不会运行,且计算机会自动提醒你声明变量。在VBE编辑界面,通过工具--》选项--》编辑器--》勾选“要求变量声明”,则每个模块都会在第一句自动写下“OptionExplicit”(2)Static关键字:声明变量为......
  • 前端进化笔记-JavaScript(一)
    简介:实现:三部分ecmascript语言核心DOM文档对象模型BOM浏览器对象模型DOM:用于html的应用程序接口(API),把整个页面映射成一个多层节点结构。例如:<html> <head> <title>samplepage</title> </head> <body> <p>helloworld</p> </body></html>DOM......
  • SpringMVC 框架总结笔记
    第一章初识SpringMVC1.1SpringMVC概述SpringMVC是Spring子框架SpringMVC是Spring为【展现层|表示层|表述层|控制层】提供的基于MVC设计理念的优秀的Web框架,是目前最主流的MVC框架。SpringMVC是非侵入式:可以使用注解让普通java对象,作为请求处理器【Controller】......
  • 学习笔记10
    第21章存储秘密21.1磁盘存储秘密的一个很直接的办法是把秘密存储在计算机的硬盘上或其他永久存储介质上,这是可行的,但是任何使用此电脑的人都能使用该密钥。一个更好的解决方案是让Alice把密钥存储在她的PDA或智能手机上。这些设备很少会借给别人使用,而且无论去哪里都会随......
  • Vue学习笔记之Node Sass version 8.0.0 is incompatible with 4.0.0错误
    输入以下两个命令:npmuninstallnode-sassnpmi-Dsass注:Mac环境如果进行了系统升级,需要重新安装Xcode,执行命令xcode-selectinstall不然会出现如下的错误Mac解决gyp:NoXcodeorCLTversiondetected!报错 如果出现python2的错误gypverb`which`failedE......
  • HTML入门学习笔记
    HTML学习笔记详解01初识HTMLHTMLHTML,英文全称为HyperTextMarkupLanguage,中文翻译为超文本标记语言,其中超文本包括:文字,图片,音频,视频,动画等目前目前主流使用的是HTML5+CSS3HTML的优势主流浏览器都支持微软GOOGLE苹果市场的需求跨平台(类似JVM)W3C标准......
  • HTML-CSS笔记
    HTML一、网页的基本结构和基础1、html基础<!doctypehtml><html> <head> <!--可以通过meta标签来设置网页的字符集,避免乱码的问题--> <metacharset="UTF-8"/> <title>网页的基本结构</title> </head> <body> <!-- 迭代 网页的版本......
  • LCA(最近公共祖先)学习笔记
    前言没想到干完lca的时间比tarjan的还要长(我不能这么弱下去了!!)前置知识dfs序这东西有点类似于时间戳(dfn),但是它分为两部分(回溯之前和回溯之后)。并且dfs序还分为两种。这里只介绍一倍的dfs序。如上图,蓝色代表左端点,红色代表右端点,(学过Tarjan的都知道),蓝色其实就是这棵树的dfn(......