Skip to content
🔥 更新时间:

地狱难度挑战

这些挑战是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中选择列K
  • From<T, W> 指定要查询的表T和可选的Where条件
  • Where<C> 使用特殊的标记类型标识过滤条件
  • FilterTable<T, C> 根据条件C过滤表T中的行
  • FilterField<V, P, C> 检查字段值是否满足过滤条件

我们会不断添加更多地狱难度的挑战,请定期查看更新!

返回挑战列表

Contributors

The avatar of contributor named as fengzebing fengzebing

Changelog

本站访客数 人次 本站总访问量