体操基础
体操全集: https://github.com/type-challenges/type-challenges/blob/main/README.zh-CN.md
Partial
// Partial<T>将T的所有属性变成可选的。 type Partial<T> = { [P in keyof T]?: T[P]; }
解释:
in: in的用法是要用在类型遍历中形如上图这种{} 下 in 后面要是一个string、number、symbol联合类型,比如你可以keyof '1213'|'123123'|'13123' 但是不能p in [];
keyof 是将一个接口(interface)或者类型(type)转变成他的key的联合类型
T[p] 类似于js本身语法 T是个对象,P是他的key T[p] 就是他原来的值
Exculde
// Exculde<T, U>排除联合类型T 中 属于U的类型 type Exculde<T, U> = T extends U ? never : T;
解释:
never 联合其他类型是没有never的
T extends U ?never : T 属于条件类型 知识点:分布式条件类型
这里有个思考就是1 的解题思路是{} {}中遍历key的形式。2的解题思路是条件类型 他俩有什么区别? 答 1 是对接口中key的筛选或处理,比如Pick(筛选出符合条件的key)、Record(给key赋值),2 是对联合类型的筛选 比如Exculde(例如:将'a'|'b' 筛选成'a')
Require 将类型T所有属性设为require
type Require<T> = { [p in keyof T]-?: T[p]; }
Pick<T, K> 从类型T 中挑选部分属性K 来构造新的类型
type Pick<T, K> = { [p in keyof K]: T[p]; }
Extract<T, U> 从类型T中提取所有可以赋值给U的类型
type Extract<T, U> = T extends U ? T : never;
Omit<T, K> 从类型T中剔除所有能赋值给K的属性
type Omit<T, K> = { [p in Exculde<keyof T, K>] : T[p]; } // 但是这里面还有一种更有意思的写法 值得注意的是这里 as 对 T 起到了收敛子集的作用 type Omit<T, K> = { [p in K as (T extends K ? never: T)] : T[p] } // 另外还有一种更长用的 type OmitV<T, K> = { [p in keyof T as (T[p] extends K ? p : never)]: T[p]; }
NonNullable 从T中剔除null和undefined
ReturnType
type ReturnType<T extends (...arg: any) => any> = T extends (...arg:any) => infer R ? R : any;
infer 这个东西必须用到条件语句中,用来推断。而且他有自己的作用域
实现一个判断startWith<T, U>
// 网上流行的版本 其中string做为特殊关键字参与了结构; type startWith<Prefix> = `${Prefix}${string}`; type a = '/as' type b = a extends startWith<'/'> ? true; false; // 自己实现的版本 type startWith<T, U extends string> = T extends `${U}${infer R}` ? true: false; type c = startWith<a, '/'>
使用映射类型实现window.addEvent
type EventType1 = { target: Element; } type EventType2 = { target: HTMLInputElement; } type EventFunctionMap = { type1: EventType1; type2: EventType2; } type EventList = keyof EventFunctionMap; type addEvent<T extends EventList> = ( type: T, listener: ( arg: EventFunctionMap[T], ) => void, ) => void; // 附上一个 不用映射类型的
PickByType
type OnlyBoolean = PickByType<{ name: string count: number isReadonly: boolean isEnable: boolean }, boolean> // { isReadonly: boolean; isEnable: boolean; } // 实现: type PickByType<T, U> = { [K in keyof T as T[K] extends U ? K : never]: T[K] }
很有意思的是拿as 约束了 key遍历的数量
Mutable
// Mutable 把所有的属性改为非只读,即去掉readonly 可以使用-操作符 type Mutable<T extends object> = { -readonly [K in keyof T]: T[K] }
Length of String
type Split<S extends string> = S extends `${infer F}${infer R}` ? [F, ...Split<R>] : [] type LengthOfString<S extends string> = Split<S>['length']
思路: ts支持通过length变量取数组的长度,所以核心本质是字符串转数组,然后取长度; 另外ts中迭代基本就是模拟计算机手动压栈的过程;
Last updated
Was this helpful?