困难难度挑战
这些挑战需要对TypeScript类型系统有深入的理解,并且能够创造性地组合多种类型技术。挑战这一级别需要较强的思考能力和TypeScript类型系统经验。
挑战列表
1. 联合类型中的字符串字面量
要求:从联合类型 T 中提取出所有的字符串字面量类型。
例子:
typescript
type T0 = string | number | boolean | null | undefined
type T1 = 'a' | 'b' | 'c' | 1 | 2 | true | false | null
type T2 = string | 'a' | 'b' | 'c'
type R0 = StringLiteral<T0> // never
type R1 = StringLiteral<T1> // 'a' | 'b' | 'c'
type R2 = StringLiteral<T2> // 'a' | 'b' | 'c'解决方案:
typescript
type StringLiteral<T> = T extends string
? string extends T
? never
: T
: never解释:
- 首先检查
T是否可以赋值给string - 如果可以,再检查
string是否可以赋值给T - 如果
string可以赋值给T,则T包含整个string类型,不是字面量类型,返回never - 如果
string不能赋值给T,则T是字符串字面量类型,返回T - 如果
T不能赋值给string,则T不是字符串类型,返回never
2. CamelCase 转换
要求:实现 CamelCase<T> 类型,将蛇形命名字符串转换为驼峰命名。
例子:
typescript
type camelCase1 = CamelCase<'hello_world'> // 'helloWorld'
type camelCase2 = CamelCase<'foo_bar_baz'> // 'fooBarBaz'解决方案:
typescript
type CamelCase<S extends string> = S extends `${infer P}_${infer Q}`
? `${P}${CamelCase<Capitalize<Q>>}`
: S解释:
- 使用模板字符串类型检查
S是否包含下划线 - 如果包含,提取下划线前的部分
P和下划线后的部分Q - 将结果构造为
P连接上Q的首字母大写形式,并递归处理剩余部分 - 如果不包含下划线,直接返回原字符串
3. 实现 Currying 类型
要求:实现一个类型 Currying,将多参数函数转换为柯里化函数类型。
例子:
typescript
type Fn = (a: number, b: string, c: boolean) => number
type CurriedFn = Currying<Fn>
// (a: number) => (b: string) => (c: boolean) => number解决方案:
typescript
type Currying<F> = F extends (...args: infer Args) => infer Return
? Args extends [infer First, ...infer Rest]
? (arg: First) => Currying<(...args: Rest) => Return>
: Return
: never解释:
- 首先提取函数
F的参数类型Args和返回类型Return - 检查参数数组是否可以分解为第一个参数
First和剩余参数Rest - 如果可以,返回一个接收
First的函数,该函数返回对剩余参数的柯里化函数 - 如果没有更多参数,直接返回原函数的返回类型
Return
4. 字符串连接
要求:实现一个类型 Join<T, D>,将字符串元组 T 中的元素用连接符 D 连接起来。
例子:
typescript
type Result = Join<['a', 'p', 'p', 'l', 'e'], '-'> // 'a-p-p-l-e'解决方案:
typescript
type Join<T extends string[], D extends string> = T extends [infer F extends string, ...infer R extends string[]]
? R['length'] extends 0
? F
: `${F}${D}${Join<R, D>}`
: ''解释:
- 检查元组
T是否可以分解为第一个元素F和剩余元素R - 如果剩余元素数组长度为0,则只返回第一个元素
- 否则,返回第一个元素、连接符和对剩余元素递归调用
Join的结果 - 如果输入是空数组,返回空字符串
我们会不断添加更多困难难度的挑战,请定期查看更新!
