类型体操代码片段
"TS类型体操"通常是指在TypeScript中使用类型系统的一种技巧,以更好地利用TypeScript的类型检查功能。TypeScript是JavaScript的一个超集,它添加了静态类型定义,使得在开发大型应用程序时更容易进行类型检查和调试。TS类型体操是指利用TypeScript强大的类型系统,通过巧妙的类型定义和使用技巧,以及一些特殊的类型操作,来实现更高级、更复杂的类型检查和类型推断。
最近为了更好的学习ts的类型系统,开始练习类型体操。地址:
https://github.com/type-challenges/type-challenges
记录一些常用的类型技巧
类型体操包括哪些内容?
TS类型体操可以包括以下内容:
类型推断和类型注解:TypeScript允许你在变量、函数参数、函数返回类型等地方进行类型注解,同时也有一定的类型推断机制,可以根据上下文自动推断类型。
联合类型和交叉类型:通过联合类型(Union Types)和交叉类型(Intersection Types),可以将多种类型组合在一起,实现更灵活的类型定义。
泛型:使用泛型可以在多个地方重用相同的类型,增加代码的灵活性和重用性。
条件类型:条件类型是TypeScript中的高级类型,允许根据其他类型来选择其中一种类型定义。
映射类型:映射类型允许你从一个现有的类型创建一个新的类型,其中每个属性都可以按照一定的规则转换。
类型守卫:使用类型守卫可以在运行时检查类型,帮助你在代码中处理不同的类型情况。
keyof 操作符:keyof 操作符用于获取对象类型的所有键,它常用于泛型约束和类型操作。
类型操作符:TypeScript提供了一些类型操作符,如keyof、typeof、in等,用于操作和获取类型信息。
索引类型:索引类型可以用于访问对象的属性,并保留其类型信息。
TS类型体操是利用TypeScript强大类型系统的一种技巧和思维方式,它可以帮助开发者更好地利用类型检查来提高代码的可靠性和健壮性。
代码片段
判断两个类型是否相等
export type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2
? true
: false
遍历一个数组的类型
type TupleToObject<T extends readonly any[]> = {
// 遍历写法:[key in T[number]]
[key in T[number]]: key;
};
遍历联合类型
// 对于联合类型,extends 语法,会把T中每一个类型都拿出来进行一次判断
type MyExclude<T, U> = T extends U ? never : T;
// 再来个例子,实现泛型IsUnion<T>,它可以判断T是否为联合类型。T 如果是联合类型,会分成多个子类型和B 比较,然后再判断
// B 的所有类型是不是和和T 的子类型一致,这里利用[B] 阻止第二个extends 做类型拆分。
type IsUnion<T, B = T> = T extends B ? [B] extends [T] ? false : true : never;
// 测试
type case1 = IsUnion<string> // false
type case2 = IsUnion<string|number> // true
type case3 = IsUnion<[string|number]> // false
字符串类型判断
// 对于字符串的类型判断,可以用extends 来判断,
type TrimsChars = " " | "\n" | "\t";
type TrimLeft<S extends string> = S extends `${TrimsChars}${infer R}`
? TrimLeft<R>
: S;
合并数组
type Concat<T extends any[], U extends any[]> = [...T, ...U]
生成数组
type newArr<T extends number, A extends any[] = []> =
A['length'] extends T
? A
: newArr<T, [...A, '']>
type newArr<5> = ['','','','','']
判断类型相等
// https://github.com/microsoft/TypeScript/issues/27024#issuecomment-421529650
type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2
? true
: false
字符串转数字
// 这里也是利用了字符串模版,比较两个字符串,还用到了infer 来推导数字类型
type ParseInt<T extends string> = T extends `${infer D extends number}` ? D : never;
反转字符串
// S extends `${infer First}${infer Rest}` 可以把字符串分成前半部分和最后一个字符串,这个时候就可以用递归解决问题
// 类型体操关于字符串的要灵活利用字符串模版类型 切分出来要处理的和处理完的
type ReverseString<S extends string> = S extends `${infer First}${infer Rest}` ? `${ReverseString<Rest>}${First}` : ''
判断一个类型是对象,数组,还是基本数据类型或者函数
// 基本类型,或者函数的key是never
type IsObjectOrArray<T> = keyof T extends never ? false : true
// 例子实现递归的readonly, 这里可以用这个技巧判断是不是对象
type DeepReadonly<T> = keyof T extends never ? T : readonly [P in keyof T] : DeepReadonly<T[P]>