地狱难度挑战
这些挑战是TypeScript类型体操中最具挑战性的问题,需要对TypeScript类型系统有极深入的理解,掌握各种高级类型编程技术,并能将它们组合使用解决复杂问题。
注意
这些挑战非常复杂,建议在掌握简单、中等和困难难度的挑战后再尝试挑战。
挑战列表
1. 字符串解析器
要求:实现一个类型级别的字符串解析器 ParsePrintFormat
,用于解析printf
格式的字符串并提取对应的参数类型。
例子:
typescript
type Format = '%d | %f | %s'
type Result = ParsePrintFormat<Format> // [number, number, string]
解决方案:
typescript
type ControlsMap = {
'd': number;
'f': number;
's': string;
'c': string;
}
type ParsePrintFormat<S extends string> =
S extends `${string}%${infer C}${infer Rest}`
? C extends keyof ControlsMap
? [ControlsMap[C], ...ParsePrintFormat<Rest>]
: ParsePrintFormat<Rest>
: []
解释:
- 首先定义一个映射类型
ControlsMap
,将格式控制字符映射到对应的TypeScript类型 - 使用模板字符串类型和条件类型递归解析字符串
- 如果找到格式标记
%d
、%f
等,从映射中查找对应类型并添加到结果数组中 - 递归处理剩余字符串,直到处理完所有字符
2. 实现 Inclusive Range
要求:实现一个 Range<F, T>
类型,生成从 F 到 T 的数字元组类型(包含 F 和 T)。
例子:
typescript
type result = Range<2, 5> // [2, 3, 4, 5]
解决方案:
typescript
type Range<F extends number, T extends number, Acc extends number[] = [], C extends number = F> =
Acc['length'] extends T
? [...Acc, T]
: C extends T
? [...Acc, C]
: Range<F, T, [...Acc, C], AddOne<C>>
type AddOne<N extends number> = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...number[]][N]
解释:
- 使用递归类型生成数字范围
- 使用
Acc
(累加器)参数跟踪已生成的数字 - 使用
C
(当前)参数跟踪当前处理的数字 - 在每次递归中,检查是否达到目标数字 T
- 使用索引访问类型实现整数加法
3. 千分位分隔符
要求:实现 ThousandSeparator<T>
,将一个数字或者字符串数字按照每三位添加逗号分隔符。
例子:
typescript
type Result1 = ThousandSeparator<12345> // '12,345'
type Result2 = ThousandSeparator<9999999> // '9,999,999'
解决方案:
typescript
type ThousandSeparator<T extends string | number, S extends string = `${T}`> =
S extends `${infer L}${infer R}`
? ThousandSeparatorHelper<S, ''>
: S
type ThousandSeparatorHelper<S extends string, Result extends string = ''> =
S extends `${infer D1}${infer D2}${infer D3}${infer Rest}`
? Rest extends ''
? `${Result}${D1}${D2}${D3}`
: ThousandSeparatorHelper<Rest, `${Result}${D1}${D2}${D3},`>
: S extends `${infer Rest}`
? `${Result}${Rest}`
: Result
解释:
- 将输入转换为字符串
- 使用辅助类型
ThousandSeparatorHelper
处理千分位分隔 - 每次从字符串头部提取3个字符,并在后面添加逗号
- 递归处理剩余字符,直到处理完所有字符
- 对于不足3位的剩余字符,直接添加到结果中
4. 实现 SQL 类型
要求:实现一个类型级别的SQL查询语句类型系统。
例子:
typescript
interface Table {
name: string
age: number
address: string
}
type Query = Select<'name' | 'age', From<Table, Where<{ age: 18 }>>>
// { name: string; age: number }
解决方案:
typescript
type Select<K, T> =
K extends keyof T
? { [P in K]: T[P] }
: never
type From<T, W = {}> =
W extends Where<infer C>
? FilterTable<T, C>
: T
type Where<C> = { __where: C }
type FilterTable<T, C> =
{ [P in keyof T as FilterField<T[P], P, C>]: T[P] }
type FilterField<V, P extends PropertyKey, C> =
P extends keyof C
? V extends C[P]
? P
: never
: P
解释:
Select<K, T>
从表T中选择列KFrom<T, W>
指定要查询的表T和可选的Where条件Where<C>
使用特殊的标记类型标识过滤条件FilterTable<T, C>
根据条件C过滤表T中的行FilterField<V, P, C>
检查字段值是否满足过滤条件
我们会不断添加更多地狱难度的挑战,请定期查看更新!