本文主要是介绍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的类型)
示例:
- 实现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] // 可以获取元组的所有类型的集合
示例:
- 实现Append<Tuple, Element>
type Append<Tuple extends any[], Element> = [...Tuple, Element]type a = Append<[1,string], true> // [1, string, true]
- 返回长度+1
type Length<Tuple extends any[]> = [any, ...Tuple]['length']type a = Length<[1, 2]> // 3
- 将元组转化为数组
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> = ...;
示例:
- 判断输入的是否是数组
type isArray<Arr> = Arr extends Array<any> ? true : false;type a = isArray<[1, 2, 3]>; // true
type b = isArray<1>; // false
```
- 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> : {};
本质就是:每次只处理第一个元素,然后不断递归剩余元素
示例:
- 实现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";}]*/
- 实现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]
- 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"
示例:
- 判断字符串开头
type startWith<str extends string,T extends string
> = str extends `${T}${infer rest}` ? true : false
type res = startWith<'abc', 'a'> // type res = true
- 首字母大写
type UppercaseFirst<str extends string> = str extends `${infer F}${infer R}`? `${Uppercase<F>}${R}`: strtype res = UppercaseFirst<'hello'> // type res = "Hello"
- 文本替换
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"
- 键值对转索引类型
例如: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'>
- 对象索引转大写
interface B {aaa: 1;bbb: 2;
}
type UpperKeys = {[K in keyof B as Uppercase<K>]: B[K]
}type res = UpperKeys // { AAA: 1; BBB: 2; }
- 只获取函数的索引
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类型体操笔记的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!