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

相关文章

MySQL 中查询 VARCHAR 类型 JSON 数据的问题记录

《MySQL中查询VARCHAR类型JSON数据的问题记录》在数据库设计中,有时我们会将JSON数据存储在VARCHAR或TEXT类型字段中,本文将详细介绍如何在MySQL中有效查询存储为V... 目录一、问题背景二、mysql jsON 函数2.1 常用 JSON 函数三、查询示例3.1 基本查询3.2

利用Python快速搭建Markdown笔记发布系统

《利用Python快速搭建Markdown笔记发布系统》这篇文章主要为大家详细介绍了使用Python生态的成熟工具,在30分钟内搭建一个支持Markdown渲染、分类标签、全文搜索的私有化知识发布系统... 目录引言:为什么要自建知识博客一、技术选型:极简主义开发栈二、系统架构设计三、核心代码实现(分步解析

Pydantic中Optional 和Union类型的使用

《Pydantic中Optional和Union类型的使用》本文主要介绍了Pydantic中Optional和Union类型的使用,这两者在处理可选字段和多类型字段时尤为重要,文中通过示例代码介绍的... 目录简介Optional 类型Union 类型Optional 和 Union 的组合总结简介Pyd

Oracle数据库常见字段类型大全以及超详细解析

《Oracle数据库常见字段类型大全以及超详细解析》在Oracle数据库中查询特定表的字段个数通常需要使用SQL语句来完成,:本文主要介绍Oracle数据库常见字段类型大全以及超详细解析,文中通过... 目录前言一、字符类型(Character)1、CHAR:定长字符数据类型2、VARCHAR2:变长字符数

Spring Boot 配置文件之类型、加载顺序与最佳实践记录

《SpringBoot配置文件之类型、加载顺序与最佳实践记录》SpringBoot的配置文件是灵活且强大的工具,通过合理的配置管理,可以让应用开发和部署更加高效,无论是简单的属性配置,还是复杂... 目录Spring Boot 配置文件详解一、Spring Boot 配置文件类型1.1 applicatio

Python如何查看数据的类型

《Python如何查看数据的类型》:本文主要介绍Python如何查看数据的类型方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录python查看数据的类型1. 使用 type()2. 使用 isinstance()3. 检查对象的 __class__ 属性4.

Python容器类型之列表/字典/元组/集合方式

《Python容器类型之列表/字典/元组/集合方式》:本文主要介绍Python容器类型之列表/字典/元组/集合方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1. 列表(List) - 有序可变序列1.1 基本特性1.2 核心操作1.3 应用场景2. 字典(D

Python如何在Word中生成多种不同类型的图表

《Python如何在Word中生成多种不同类型的图表》Word文档中插入图表不仅能直观呈现数据,还能提升文档的可读性和专业性,本文将介绍如何使用Python在Word文档中创建和自定义各种图表,需要的... 目录在Word中创建柱形图在Word中创建条形图在Word中创建折线图在Word中创建饼图在Word

SpringBoot接收JSON类型的参数方式

《SpringBoot接收JSON类型的参数方式》:本文主要介绍SpringBoot接收JSON类型的参数方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、jsON二、代码准备三、Apifox操作总结一、JSON在学习前端技术时,我们有讲到过JSON,而在

Rust中的BoxT之堆上的数据与递归类型详解

《Rust中的BoxT之堆上的数据与递归类型详解》本文介绍了Rust中的BoxT类型,包括其在堆与栈之间的内存分配,性能优势,以及如何利用BoxT来实现递归类型和处理大小未知类型,通过BoxT,Rus... 目录1. Box<T> 的基础知识1.1 堆与栈的分工1.2 性能优势2.1 递归类型的问题2.2