1. 什么是类型体操
类型体操的本质就是在自己的大脑中训练各种各样的类型,从而使自己更加灵活的使用各种各样的类型
1.1 体操的基本原理
// 基础的体操
// type A = 1
// type B = 1 | 2
// type Result = A extends B ? true : false
// 复杂一点的体操
// type A = 1
// type B = 1 | 2
// type C = 3
// type D = 3 | 4
// // 表示 if (A <= B) and (C <= D) ...
// type Result = A extends B ? (C extends D ? 'true, true' : 'true, false') : C extends D ? 'false, true' : 'false, false'
// 空元组
type A = []
type IsEmptyArray<Arr extends unknown[]> = Arr['length'] extends 0 ? true : false
type Result = IsEmptyArray<A>
// 非空元组
// 方式一
type IsNotEmptyArray<Arr extends unknown[]> = Arr['length'] extends 0 ? false : true
type Result1 = IsNotEmptyArray<[1, 2]>
// 方式二
// type NotEmpty<Arr extends unknown[]> = Arr extends [...unknown[], unknown] ? true : false
// X 可以为空
type NotEmpty<Arr extends unknown[]> = Arr extends [...infer X, infer Y] ? true : false
type Result2 = NotEmpty<[1]>
// 递归
type B = ['ji', 'ni', 'tai', 'mei']
type Reverse<Arr extends unknown[]> = Arr extends [...infer Rest, infer Last] ? [Last, ...Reverse<Rest>] : Arr
type Result3 = Reverse<B>
// Result is ['mei', 'tai', 'ni', 'ji']
// 模式匹配 + infer '引用'
type Tuple = ['ji', 'ni', 'tai', 'mei']
type Result4 = Tuple extends [infer First, ...infer Last] ? First : never
// 如果不想使用Last, 可以只写上类型
type Result5 = Tuple extends [infer First, ...string[], infer Last] ? Last : never
type C = ['ji', 'ni', 'mei']
/**
* 等价于下面
* type C = { 0: 'ji', 1: 'ni', 2: 'mei', length: 3 }
* 任何数组都是一个对象
*/
1.2 元组的基本体操
// 扩展元组
// type A = [1, 2, 3, 4]
// type B = [...A, 2]
type A = [1, 2, 3, 4]
type B = [5, 6, 7]
type C = [...A, ...B]
type D = [1, 2, 3, 4]
// 注意 1,2,3,4 都是类型,不是值
type Last<T extends unknown[]> = T extends [...unknown[], infer L] ? L : never
type NotLast<T extends unknown[]> = T extends [...infer X, unknown] ? X : never
type Result = Last<D>
type Result1 = Last<[]>
type Result2 = NotLast<D>
// 这种写法会报错
// ts 没有提供 - 操作符
// type Last1<T extends unknown[]> = T[T['length'] - 1]
1.3 字符串的基本体操
// type A = 'fang'
// type B = Capitalize<A>
// type C = 'ji' | 'ni' | 'tai' | 'mei'
// // 当联合类型和泛型结合的时候会对每一个类型做分配率
// type D = Capitalize<C>
// 以下几个全是ts内置的方法
/**
* 全变成大写
*/
type Uppercase<S extends string> = intrinsic
/**
* 全变成小写
*/
type Lowercase<S extends string> = intrinsic
/**
* 首字母大写
*/
type Capitalize<S extends string> = intrinsic
/**
*首字母小写
*/
type Uncapitalize<S extends string> = intrinsic
// 模板字符串
// type A = 'ji'
// type B = 'ni'
// type C = 'tai'
// type D = 'mei'
// type X = `${A} ${B} ${C} ${D}`
// 获取字符串的第一项
type A = 'ji ni tai meix'
type First<T extends string> = T extends `${infer F}${string}` ? F : never
type Result = First<A> // j
// 如何获取字符串的最后一个?
// 我们可以获取元组的最后一项
//字符串可以转化为元组
// 我们获取字符串的最后一项
type LastOfTuple<T extends unknown[]> = T extends [...infer _, infer L] ? L : never
type StringToTuple<S extends string> = S extends `${infer F}${infer R}` ? [F, ...StringToTuple<R>] : []
type LastOfString<S extends string> = LastOfTuple<StringToTuple<S>>
type Result2 = LastOfString<A>
1.4 infer
type Flatten<Type> = Type extends Array<infer Item> ? Item : Type
type X = Flatten<Array<number>>
// https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#handbook-content
1.5 递归的层数限制
type A = [
'ji',
'ni',
'tai',
'mei',
'ji',
'ni',
'tai',
'mei',
'ji',
'ni',
'tai',
'mei',
'ji',
'ni',
'tai',
'mei',
'ji',
'ni',
'tai',
'mei',
'ji',
'ni',
'tai',
'mei',
'ji',
'ni',
'tai',
'mei',
'ji',
'ni',
'tai',
'mei',
'ji',
'ni',
'tai',
'mei',
'ji',
'ni',
'tai',
'mei',
'ji',
'ni',
'tai',
'mei',
'ji',
'ni',
'tai',
'mei'
// 'ji'
]
type Reverse<Arr extends unknown[]> = Arr extends [...infer Rest, infer Last] ? [Last, ...Reverse<Rest>] : Arr
// 递归最多48层
type Result3 = Reverse<A>
1.6 字符串转元组和联合
// 字符串转联合
type StringToUnion<S extends string> = S extends `${infer First}${infer Rest}` ? First | StringToUnion<Rest> : never
type Result = StringToUnion<'jinitaimei'>
// 注意: 联合类型自动去重
// 字符串转元组
type StringToTuple<S extends string> = S extends `${infer First}${infer Rest}` ? [First, ...StringToTuple<Rest>] : []
type Result1 = StringToTuple<'jinitaimei'>