TS试炼-9
摘要:
包含:Parse URL Params(解析URL参数)、获取数组的中间元素、找出目标数组中只出现过一次的元素、统计数组中的元素个数、整数、将类型为字面类型(标签类型)的属性,转换为基本类型、DeepMutable(深度可变)、All(元组每项与传入类型相同)、Filter(过滤)、FindAll(获取所有下标)
1、Parse URL Params(解析URL参数)
ts
ParseUrlParams<':id'> // id
ParseUrlParams<'posts/:id'> // id
ParseUrlParams<'posts/:id/:user'> // id | user
实现
ts
type ParseUrlParams<T extends string> = T extends `${string}:${infer P}` // 通过:分割,拿到剩余参数
? P extends `${infer F}/${infer R}` // 判断剩余参数后是否有/,有就根据/分割
? F | ParseUrlParams<R> // 有/就将/前的与剩余参数联合
: P // 没有/,直接返回:后的
: never;
2、获取数组的中间元素
ts
type simple1 = GetMiddleElement<[1, 2, 3, 4, 5]>, // 返回 [3]
type simple2 = GetMiddleElement<[1, 2, 3, 4, 5, 6]> // 返回 [3, 4]
第一种方案
ts
type GetMiddleElement<T extends unknown[]> = T['length'] extends 0 | 1 | 2 // 元组长度小于3时,都是返回自身
? T
: T extends [any, ...infer C, any] // 长度大于等于3时,去除两边的,保留中间
? GetMiddleElement<C> // 对中间的参数递归,得到最终结果
: never;
第二种方案
ts
type GetMiddleElement<T extends any[]> = T extends [infer L, ...infer M, infer R] // 判断T最少有两个元素
? M extends [] // 判断是否只有两个元素
? [L, R] // 只有两个直接返回
: GetMiddleElement<M> // 递归执行剩余项
: T; // 少于两个元素,直接返回
3、找出目标数组中只出现过一次的元素
ts
FindEles<[1, 2, 2, 3, 3, 4, 5, 6, 6, 6]> // [1, 4, 5]
FindEles<[2, 2, 3, 3, 6, 6, 6]> // []
FindEles<[1, 2, 3]> // [1, 2, 3]
FindEles<[number, 1, 2]> // [number, 1, 2]
FindEles<[1, 2, number, number]> // [1, 2]
实现
ts
type IsExist<T, C> = T extends T ? (Equal<T, C> extends true ? true : false) : never;
type FindEles<T extends any[], U extends unknown[] = []> = T extends [infer F, ...infer R]
? IsExist<[...U, ...R][number], F> extends false // 判断当前是否在剩余参数及已存在的参数内
? [F, ...FindEles<R, U>] // 不在里面,则添加到结果
: FindEles<R, [...U, F]> // 在里面,不添加
: [];
4、统计数组中的元素个数
ts
type Simple1 = CountElementNumberToObject<[]> // return {}
type Simple2 = CountElementNumberToObject<[1,2,3,4,5]> // { 1: 1, 2: 1, 3: 1, 4:1 , 5: 1 }
type Simple3 = CountElementNumberToObject<[1,2,3,4,5,[1,2,3]]> // { 1: 2, 2: 2, 3: 2, 4:1 , 5: 1 }
第一种方式
ts
type CountElementNumberToObject<T extends unknown[], U extends Record<PropertyKey, 0[]> = {}> = T extends [infer F, ...infer R] // 判断是否结束
? [F] extends [never] // 判断当前是否为never
? CountElementNumberToObject<R, U> // 为never,则忽略,继续执行后续
: F extends any[] // 如果当前是数组
? CountElementNumberToObject<[...F, ...R], U> // 将数组平铺,继续执行
: CountElementNumberToObject<R, { // 不是数组,准备统计
[P in keyof U | F & PropertyKey]: P extends keyof U // 判断是否为新增属性
? (P extends F ? [...U[P], 0] : U[P]) // 不是新增属性,为对应项元组添加长度
: [0]; // 新增属性,初始化元组
}>
: {
[P in keyof U]: U[P]['length']; // 结束,返回统计结果
};
第二种方式
ts
// 平铺数组
type Flat<T> = T extends [infer F, ...infer R] ? F extends any[] ? [...Flat<F>, ...Flat<R>] : [F, ...Flat<R>] : T;
// 统计每一项,在平铺数组中的数量
type Count<T, O, U extends 0[] = []> = T extends [infer F, ...infer R] ? F extends O
? Count<R, O, [...U, 0]>
: Count<R, O, [...U]>
: U['length'];
// 返回统计结果
type CountElementNumberToObject<T extends any[], U extends any[] = Flat<T>> = {
[K in U[number]]: Count<U, K>;
};
5、整数
ts
Integer<1> // 1
Integer<1.1> // never
Integer<1.0> // 1
实现
ts
// 常规思路
type Integer<T extends number> = number extends T ? never : `${T}` extends `${string}.${string}` ? never : T
// 学习新知识:bigint
type Integer<T extends number> = `${T}` extends `${bigint}` ? T : never
6、将类型为字面类型(标签类型)的属性,转换为基本类型
ts
// { name: string, age: number, married: boolean, addr: { home: string, phone: string } }
type PersonInfo = { name: 'Tom', age: 30, married: false, addr: { home: '123456', phone: '13111111111' } }
第一种方式(valueOf)
ts
type ToPrimitive<T>
= T extends Function ? Function
: T extends object ? { [K in keyof T]: ToPrimitive<T[K]> }
: T extends { valueOf(): infer R } ? R
: T
第二种方式
ts
type ToPrimitive<T> = {
[P in keyof T]: T[P] extends string
? string
: T[P] extends number
? number
: T[P] extends boolean
? boolean
: T[P] extends Function
? Function
: T[P] extends object
? ToPrimitive<T[P]>
: T[P];
};
7、DeepMutable(深度可变)
ts
DeepMutable<{ readonly a: string, readonly b: { readonly c: number }> // { a: string, b: { c: number }
实现
ts
type DeepMutable<T extends object> = {
-readonly [P in keyof T]: T[P] extends Function ? T[P] : T[P] extends object ? DeepMutable<T[P]> : T[P]
}
type DeepMutable<T extends object> = T extends Function ? T : {
-readonly [P in keyof T]: T[P] extends object ? DeepMutable<T[P]> : T[P]
}
8、All(元组每项与传入类型相同)
ts
All<[1, 1, 1], 1> // 应与 true 相同
All<[1, 2, 1], 1> // 应与 false 相同
实现
ts
type All<T extends unknown[], V> = T extends [infer F, ...infer R] ? Equal<F, V> extends true ? All<R, V> : false : true
9、Filter(过滤)
ts
Filter<[0, 1, 2], 2> // [2]
Filter<[0, 1, 2], 0 | 1> // [0, 1]
Filter<[0, 1, 2], false | 0 | '' | null | undefined> // [0]
实现
ts
type Filter<T extends any[], P> = T extends [infer F, ...infer R] ? F extends P ? [F, ...Filter<R, P>] : Filter<R, P> : []
10、FindAll(获取所有下标)
ts
FindAll<'Collection of TypeScript type challenges', 'Type'> // [14]
FindAll<'Collection of TypeScript type challenges', 'pe'> // [16, 27]
FindAll<'Collection of TypeScript type challenges', ''> // []
FindAll<'', 'Type'> // []
FindAll<'', ''> // []
FindAll<'AAAA', 'A'> // [0, 1, 2, 3]
FindAll<'AAAA', 'AA'> // [0, 1, 2]
第一种方案
ts
// 获取字符串的长度
type StringLength<
T extends string,
U extends 0[] = []
> = T extends `${string}${infer R}` ? StringLength<R, [...U, 0]> : U['length']
type FindAll<
T extends string, // 要匹配的字符串
P extends string, // 匹配的字符
U extends string = '', // 已经匹配的字符
R extends number[] = [] // 最终结果
> = P extends ''
? [] // 如果匹配的字段为空,直接返回
: T extends `${U}${infer F}${P}${string}` // 判断字符串中是否还有符合的
? FindAll< // 有符合的,添加结果,执行后续
T, // 原字符串不变
P, // 匹配字符不变
`${U}${F}${P extends `${infer PF}${string}` ? PF : P}`, // 已匹配的字符串组合
[...R, StringLength<`${U}${F}`>] // 结果添加
>
: R // 没有符合的,直接返回结果
第二种方案
ts
type FindAll<
T extends string, // 要匹配的字符串
S extends string, // 匹配的字符
P extends 0[] = [], // 已匹配的长度
R extends number[] = [] // 结果
> = S extends ''
? [] // 如果匹配的字段为空,直接返回
: T extends `${string}${infer L}` // 将要匹配的字符串去除第一个字符,方便后续使用
? T extends `${S}${string}` // 匹配到字符开头
? FindAll<L, S, [...P, 0], [...R, P['length']]> // 已匹配长度加一,现长度添加到结果,执行后续
: FindAll<L, S, [...P, 0], R> // 已匹配长度加一,执行后续
: R // 返回结果
// 简化版本
type FindAll<
T extends string,
P extends string,
L extends 0[] = []
> = P extends ''
? []
: T extends `${string}${infer R}`
? [
...(T extends `${P}${string}` ? [L['length']] : []),
...FindAll<R, P, [0, ...L]>
]
: []
评论
0条评论
暂无内容,去看看其他的吧~