ts类型体操笔记

2024-09-01 06:12
文章标签 类型 笔记 ts 体操

本文主要是介绍ts类型体操笔记,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

ts类型体操笔记

一、infer关键字

1. infer 作用

用于推导泛型参数,并且infer的声明只能出现在extend子语句中

2. infer 用法

infer后面加变量名

例如:获取 Promise 返回的参数

interface User {name: stringage: number
}type PromiseType = Promise<User>
type GetPromiseType<T> = T extends Promise<infer U> ? U : never
type res = GetPromiseType<PromiseType> // type res = User// 多层嵌套需要结合递归实现
type PromiseType2 = Promise<Promise<Promise<User>>>
type GetPromiseType2<T> = T extends Promise<infer U> ? GetPromiseType2<U> : T
type res2 = GetPromiseType2<PromiseType2> // type res2 = User

3. infer 协变

infer 协变主要出现在对象的属性中,infer类似解构用法时,返回的是联合类型

返回的是联合类型

let obj = {name: 'wifi',age: 18
}type Bar<T> = T extends { name: infer N; age: infer A } ? [N, A] : never
// 发生infer协变就出现在当两个参数变量名相同时,都为U,U就会变为联合类型
type Bar2<T> = T extends { name: infer U; age: infer U } ? U : nevertype res2 = Bar2<typeof obj> // type res2 = string | number

4. infer逆变

infer逆变出现在函数的参数上面,返回的是交叉类型

返回的是交叉类型

type Bar<T> = T extends {a: (x: infer U) => void;b: (x: infer U) => void;
} ? U : 'asd';type res = Bar<{a: (x: number) => void;b: (x: string) => void;
}>; // type res = nevertype res2 = Bar<{a: (x: number) => void;b: (x: number) => void;
}>; // type res2 = number

5. infer妙用

例如:提取头部元素

type Arr = ['a', 'b', 'c']type First<T extends any[]> = T extends [infer One, infer Two, infer Three] ? One : []
type res = First<Arr> // type res = "a"type First2<T extends any[]> = T extends [infer First, ...any[]] ? First : []
type res2 = First2<Arr> // type res2 = "a"

二、对象

1. 遍历

对于普通对象,一般通过for in遍历。对于类型,使用keyof Object获得它所有的键,再通过in关键字遍历

// js
for (let key in obj) {}// 类型
[T in keyof Object]

2. 取值

type Object = {name: 'wifi',age: 20
}
Object['name' | 'age'] // string | number(取的就是后面wifi和20的类型)

示例:

  1. 实现ValueOf
type ValueOf<Object> = Object[keyof Object];type a = ValueOf<{ name: string; age: 20 }>;

三、元组/数组

1. 类型中的元组

1.1 取值
type Tuple = [string, number]Tuple[0] // number
Tuple[0 | 1] // string | number
1.2 收集、展开
[...Tuple1, ...Tuple2]
1.3. 长度
Tuple['length']

2. 类型中的数组

type Arr = string[];
Arr[number] // 获取数组的类型// 另一个小技巧
Tuple[number] // 可以获取元组的所有类型的集合

示例:

  1. 实现Append<Tuple, Element>
type Append<Tuple extends any[], Element> = [...Tuple, Element]type a = Append<[1,string], true>  // [1, string, true]
  1. 返回长度+1
type Length<Tuple extends any[]> = [any, ...Tuple]['length']type a = Length<[1, 2]> // 3
  1. 将元组转化为数组
type To<Tuple extends any[]> = Array<Tuple[number]>type a = To<[1,'hello', true]> // (true | 1 | "hello")[]

四、条件语句if…else…

type isNumber<T> = T extends number ? true : false
type a = isNumber<1> // true
type b = isNumber<'1'> // falsetype isNumber2<T, K> = [T, K] extends [number, number] ? true : false

上面两个语句的区别在于extends关键字上。extends关键字最直观的描述是:A extends B就代表A能否赋值给B,也就是A是否是B的子集。

这是extends的第一个作用,当作条件语句,它还有另外一个重要作用,就是做类型约束,但其本质还是判断A是否是B的子集的问题,A是B的子集。

type Fn<T extends boolean> = ...;Fn<true> // 正确
Fn<1> // 报错// 在没有约束的默认情况下可以认为是
type Fn<T extends unknown> = ...;

示例:

  1. 判断输入的是否是数组
type isArray<Arr> = Arr extends Array<any> ? true : false;type a = isArray<[1, 2, 3]>; // true
type b = isArray<1>; // false
```
  1. GetProp<Key, Object>,可能Key不存在于Object,返回undefined
type GetProp<Object, Key> = Key extends keyof Object ? Object[Key] : undefined;type a = GetProp<{ name: 'wifi'}, 'name'>; // wifi
type b = GetProp<{ name: 'wifi'}, 'age'>; // undefined

五、infer类似解构赋值

1. 使用

type GetName<User> = User extends { name: infer Name } ? Name : never;

infer关键字,它可以为类型变量赋值,把参数的值提取到infer后的类型中,此时Name中保存的就是name字段的值,如果User满足类型约束,则会得到Name并返回,否则返回undefined。

2. infer在元组中的应用也很多:

type getFirst<T> = T extends [infer First, ...infer Rest] ? First : undefined;
type a = getFirst<[1,2,3]>; // 1type getRest<T> = T extends [infer First, ...infer Rest] ? Rest : undefined;
type a = getRest<[1,2,3]>; // 2, 3

3. 函数的参数也可以通过infer赋值:

type Params<F> = F extends (...params: infer P) => any ? P : undefined;
type a = Params<(a: string, b: number) => void>; // [a: string, b: number]

六、赋值

如果不想通过解构赋值,而是直接把一个变量赋值给另一个呢?

type Fn<T> = T extends infer P;

使用A extends infer B的意思是把A的值赋给B,并且这两个变量可以在分支语句中使用。

七、循环

在类型中,循环只能通过递归完成

// js中实现递归
const Fn = (a, b) => {flag === true ? Fn(c, d) : e;
}// ts实现
type Fn<A, B> = Flag extends true ? Fn<C, D> : E;

条件语句换成了extends关键字

例如:遍历元组,不论遍历数组还是元组,都可以通过循环完成。

type Loop<List> = List extends [infer First, ...infer Rest] ? Loop<Rest> : {};

本质就是:每次只处理第一个元素,然后不断递归剩余元素

示例:

  1. 实现map
type Maps<List> = List extends [infer First, ...infer Rest] ? [{ name: First }, ...Maps<Rest>] : []type a = Maps<['a', 'b', 'c']>
/*** [{name: "a";}, {name: "b";}, {name: "c";}]*/
  1. 实现filter
type FilterNumber<List> = List extends [infer First, ...infer Rest]? First extends number? [First, ...FilterNumber<Rest>]: FilterNumber<Rest>: []type a = FilterNumber<[1, 'a', 2, 'b', 3, true]> // [1, 2, 3]
  1. Take<Tuple, N, Output>

例如:

Take<[1,2,3], 2> => [1,2] (返回数组前两个)

Take<[1,2], 5> => [1,2] (不够就都返回)

type Take<Tuple, N, Output extends any[] = []> = Tuple extends [infer First,...infer Rest
]? Output['length'] extends N? Output // 已经等于数组长度,返回结果: Take<Rest, N, [...Output, First]> // 将剩余的元素继续递归: Output // []type a = Take<[1, 2, 3], 2> // [1, 2]

八、字符串

1. 模版字符串与extends/infer

type str = 'hello'// 获取字符串的第一个字符
type getFirst<T> = T extends `${infer First}${infer R}` ? First : never
// 获取字符串除了第一个字符
type getRest<T> = T extends `${infer First}${infer R}` ? R : never
type res = getFirst<str> // type res = "h"
type res2 = getRest<str> // type res2 = "ello"// 以y作为间隔,获取y前和y后字符串
type str2<T> = T extends `${infer Front}y${infer Last}` ? Front : never
type str3<T> = T extends `${infer Front}y${infer Last}` ? Last : never
type res3 = str2<'beyond'> // type res3 = "be"
type res4 = str3<'beyond'> // type res4 = "ond"

示例:

  1. 判断字符串开头
type startWith<str extends string,T extends string
> = str extends `${T}${infer rest}` ? true : false
type res = startWith<'abc', 'a'> // type res = true
  1. 首字母大写
type UppercaseFirst<str extends string> = str extends `${infer F}${infer R}`? `${Uppercase<F>}${R}`: strtype res = UppercaseFirst<'hello'> // type res = "Hello"
  1. 文本替换
type ReplaceOne<str extends string,from extends string,to extends string
> = str extends `${infer Front}${from}${infer Rest}`? `${Front}${to}${Rest}`: strtype res = ReplaceOne<'hello world', ' ', '!'> // type res = "hello!world"
  1. 键值对转索引类型

例如:a=1 => {a:1}

type ConverStrToRecord<str extends string> =str extends `${infer Key}=${infer Value}` ? { [k in Key]: Value } : never/*** type res = {a: "1";}*/
type res = ConverStrToRecord<'a=1'>
  1. 对象索引转大写
interface B {aaa: 1;bbb: 2;
}
type UpperKeys = {[K in keyof B as Uppercase<K>]: B[K]
}type res = UpperKeys // { AAA: 1; BBB: 2; }
  1. 只获取函数的索引
interface B {aaa: 1;bbb: 2;fun: () => true
}
type UpperKeys = {[K in keyof B as (B[K] extends Function ? K : never)]: B[K]
}/*** type res = {fun: () => true;}*/
type res = UpperKeys

这篇关于ts类型体操笔记的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1126161

相关文章

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

自定义类型:结构体(续)

目录 一. 结构体的内存对齐 1.1 为什么存在内存对齐? 1.2 修改默认对齐数 二. 结构体传参 三. 结构体实现位段 一. 结构体的内存对齐 在前面的文章里我们已经讲过一部分的内存对齐的知识,并举出了两个例子,我们再举出两个例子继续说明: struct S3{double a;int b;char c;};int mian(){printf("%zd\n",s

【编程底层思考】垃圾收集机制,GC算法,垃圾收集器类型概述

Java的垃圾收集(Garbage Collection,GC)机制是Java语言的一大特色,它负责自动管理内存的回收,释放不再使用的对象所占用的内存。以下是对Java垃圾收集机制的详细介绍: 一、垃圾收集机制概述: 对象存活判断:垃圾收集器定期检查堆内存中的对象,判断哪些对象是“垃圾”,即不再被任何引用链直接或间接引用的对象。内存回收:将判断为垃圾的对象占用的内存进行回收,以便重新使用。

flume系列之:查看flume系统日志、查看统计flume日志类型、查看flume日志

遍历指定目录下多个文件查找指定内容 服务器系统日志会记录flume相关日志 cat /var/log/messages |grep -i oom 查找系统日志中关于flume的指定日志 import osdef search_string_in_files(directory, search_string):count = 0

论文阅读笔记: Segment Anything

文章目录 Segment Anything摘要引言任务模型数据引擎数据集负责任的人工智能 Segment Anything Model图像编码器提示编码器mask解码器解决歧义损失和训练 Segment Anything 论文地址: https://arxiv.org/abs/2304.02643 代码地址:https://github.com/facebookresear

两个月冲刺软考——访问位与修改位的题型(淘汰哪一页);内聚的类型;关于码制的知识点;地址映射的相关内容

1.访问位与修改位的题型(淘汰哪一页) 访问位:为1时表示在内存期间被访问过,为0时表示未被访问;修改位:为1时表示该页面自从被装入内存后被修改过,为0时表示未修改过。 置换页面时,最先置换访问位和修改位为00的,其次是01(没被访问但被修改过)的,之后是10(被访问了但没被修改过),最后是11。 2.内聚的类型 功能内聚:完成一个单一功能,各个部分协同工作,缺一不可。 顺序内聚:

数学建模笔记—— 非线性规划

数学建模笔记—— 非线性规划 非线性规划1. 模型原理1.1 非线性规划的标准型1.2 非线性规划求解的Matlab函数 2. 典型例题3. matlab代码求解3.1 例1 一个简单示例3.2 例2 选址问题1. 第一问 线性规划2. 第二问 非线性规划 非线性规划 非线性规划是一种求解目标函数或约束条件中有一个或几个非线性函数的最优化问题的方法。运筹学的一个重要分支。2

【C++学习笔记 20】C++中的智能指针

智能指针的功能 在上一篇笔记提到了在栈和堆上创建变量的区别,使用new关键字创建变量时,需要搭配delete关键字销毁变量。而智能指针的作用就是调用new分配内存时,不必自己去调用delete,甚至不用调用new。 智能指针实际上就是对原始指针的包装。 unique_ptr 最简单的智能指针,是一种作用域指针,意思是当指针超出该作用域时,会自动调用delete。它名为unique的原因是这个