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

相关文章

IDEA如何将String类型转json格式

《IDEA如何将String类型转json格式》在Java中,字符串字面量中的转义字符会被自动转换,但通过网络获取的字符串可能不会自动转换,为了解决IDEA无法识别JSON字符串的问题,可以在本地对字... 目录问题描述问题原因解决方案总结问题描述最近做项目需要使用Ai生成json,可生成String类型

Mysql 中的多表连接和连接类型详解

《Mysql中的多表连接和连接类型详解》这篇文章详细介绍了MySQL中的多表连接及其各种类型,包括内连接、左连接、右连接、全外连接、自连接和交叉连接,通过这些连接方式,可以将分散在不同表中的相关数据... 目录什么是多表连接?1. 内连接(INNER JOIN)2. 左连接(LEFT JOIN 或 LEFT

Redis的Hash类型及相关命令小结

《Redis的Hash类型及相关命令小结》edisHash是一种数据结构,用于存储字段和值的映射关系,本文就来介绍一下Redis的Hash类型及相关命令小结,具有一定的参考价值,感兴趣的可以了解一下... 目录HSETHGETHEXISTSHDELHKEYSHVALSHGETALLHMGETHLENHSET

Python中异常类型ValueError使用方法与场景

《Python中异常类型ValueError使用方法与场景》:本文主要介绍Python中的ValueError异常类型,它在处理不合适的值时抛出,并提供如何有效使用ValueError的建议,文中... 目录前言什么是 ValueError?什么时候会用到 ValueError?场景 1: 转换数据类型场景

C# dynamic类型使用详解

《C#dynamic类型使用详解》C#中的dynamic类型允许在运行时确定对象的类型和成员,跳过编译时类型检查,适用于处理未知类型的对象或与动态语言互操作,dynamic支持动态成员解析、添加和删... 目录简介dynamic 的定义dynamic 的使用动态类型赋值访问成员动态方法调用dynamic 的

零基础学习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垃圾收集机制的详细介绍: 一、垃圾收集机制概述: 对象存活判断:垃圾收集器定期检查堆内存中的对象,判断哪些对象是“垃圾”,即不再被任何引用链直接或间接引用的对象。内存回收:将判断为垃圾的对象占用的内存进行回收,以便重新使用。