Skip to content

Commit 9973571

Browse files
authored
Merge pull request #1 from hua-bang/claude/repo-summary-011CUKYeWTxC8LfqqACkP8N9
feat(type-challenges): add KebabCase medium challenge
2 parents b6d6083 + ac4f42a commit 9973571

1 file changed

Lines changed: 100 additions & 0 deletions

File tree

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
---
2+
nav:
3+
title: Challenges
4+
path: /type-challenges
5+
group:
6+
title: Medium
7+
order: 2
8+
title: KebabCase
9+
order: 36
10+
---
11+
12+
# KebabCase
13+
14+
### 要求
15+
16+
Implement `KebabCase<T>` which converts a camelCase or PascalCase string to kebab-case.
17+
18+
For example:
19+
20+
```ts
21+
type Result1 = KebabCase<'fooBarBaz'>; // expected: 'foo-bar-baz'
22+
type Result2 = KebabCase<'FooBarBaz'>; // expected: 'foo-bar-baz'
23+
type Result3 = KebabCase<'foo'>; // expected: 'foo'
24+
```
25+
26+
### 测试用例
27+
28+
```ts
29+
import { Equal, Expect } from '@type-challenges/utils';
30+
31+
type cases = [
32+
Expect<Equal<KebabCase<'fooBarBaz'>, 'foo-bar-baz'>>,
33+
Expect<Equal<KebabCase<'FooBarBaz'>, 'foo-bar-baz'>>,
34+
Expect<Equal<KebabCase<'foo'>, 'foo'>>,
35+
Expect<Equal<KebabCase<'user2Name'>, 'user2-name'>>,
36+
Expect<Equal<KebabCase<'userName'>, 'user-name'>>,
37+
Expect<Equal<KebabCase<'getUserInfo'>, 'get-user-info'>>,
38+
Expect<Equal<KebabCase<'myAPIKey'>, 'my-a-p-i-key'>>,
39+
Expect<Equal<KebabCase<''>, ''>>,
40+
];
41+
```
42+
43+
### 解析
44+
45+
这道题的核心思路是:
46+
47+
1. **递归处理字符串**:逐个字符检查
48+
2. **识别大写字母**:当遇到大写字母时,需要在前面添加 `-` 并将其转为小写
49+
3. **边界处理**:字符串开头的大写字母不需要添加 `-`
50+
51+
关键技术点:
52+
- 使用模板字面量类型进行模式匹配
53+
- 使用 `Uncapitalize` 工具类型将首字母转小写
54+
- 使用条件类型判断字符是否为大写字母
55+
- 递归处理剩余字符串
56+
57+
实现步骤:
58+
1. 首先将首字母转为小写(使用 `Uncapitalize`
59+
2. 递归处理剩余部分,遇到大写字母时添加 `-` 并转小写
60+
3. 空字符串作为递归终止条件
61+
62+
### Answer
63+
64+
```ts
65+
// 辅助类型:将字符串转为 kebab-case(递归部分)
66+
type KebabCaseHelper<S extends string> = S extends `${infer First}${infer Rest}`
67+
? First extends Uppercase<First> // 判断是否为大写字母
68+
? First extends Lowercase<First> // 排除数字和特殊字符(它们的大小写相同)
69+
? `${First}${KebabCaseHelper<Rest>}` // 不是字母,直接拼接
70+
: `-${Lowercase<First>}${KebabCaseHelper<Rest>}` // 是大写字母,添加 - 并转小写
71+
: `${First}${KebabCaseHelper<Rest>}` // 小写字母直接拼接
72+
: S;
73+
74+
// 主类型:处理首字母并调用辅助类型
75+
type KebabCase<S extends string> = S extends `${infer First}${infer Rest}`
76+
? `${Uncapitalize<First>}${KebabCaseHelper<Rest>}`
77+
: S;
78+
```
79+
80+
### 知识点
81+
82+
- **模板字面量类型(Template Literal Types)**:使用 `${infer First}${infer Rest}` 进行字符串模式匹配
83+
- **条件类型(Conditional Types)**`T extends U ? X : Y` 进行类型判断
84+
- **内置工具类型**
85+
- `Uppercase<T>`:将字符串字面量类型转为大写
86+
- `Lowercase<T>`:将字符串字面量类型转为小写
87+
- `Uncapitalize<T>`:将首字母转为小写
88+
- **递归类型**:类型定义中引用自身来处理不定长度的字符串
89+
90+
### 扩展思考
91+
92+
这道题还可以扩展为:
93+
1. **SnakeCase**:将驼峰转为蛇形命名(`foo_bar_baz`
94+
2. **CamelCase**:将 kebab-case 转为驼峰命名
95+
3. **PascalCase**:将字符串转为帕斯卡命名
96+
97+
### tip
98+
99+
- [playground](https://www.typescriptlang.org/play?#code/PQKgUABBBMELQQJYGcoE8AOAnApmgRwBcALAewFcACAGwCMB7OegIx2CIDsBzKRqgJQQAxAFtkXAJakipAE74A5sqWkqAK2QBGalQDWyRtXoAzZM0KkKAGmQBDAK4AOSrP0AeeVAA8t0MAXv-UBqcKgEHRqAq0xAhZCojQKAv-qA6PKgPJyoBJsqAwPKgIjyoAw8qAhK6gG9yoDe8qAEXKgIPqGmpaAkHKgBdyoAXcqAhxKIhraAz7KgKDy-jj4hlLYCAAA4ewAJk0AZzUQBl7QAsMfMhiIAa9cARbuhMRV6oCq8qA6ov2JcVAZHlQA15UBkeVAHHlQHx5K0dAIwVQDcDJzkq0AOqgOpyoCY8qApPKgBTyoD+CoC08qA-gqAoPKgEYKoAU8qAmfKgJjyoC08qAZgqgBTyoAU8qA1PKgPYKoBCCoC2CqAXK6gJYKK6A6nIN3h6gCoKoBmCsN3R6AFvKgBTyoCCDo8kx6AxPKgITyoB88qAfq6A2PJfJyASQrU8tgFrymqAkAqgP4K5xU3QCaFUBweVAOQUbqpFR6AFPKgODyTyengByCoAqCs93O5-J4Af59AeHk3hpAJIVQEp5UBneXOFiBYOIiKhEOAADIBgOJDlJJMMNQDQ8qIroAAckAr0BYACpJAAabLMvC86DXpjXRtAi9AdHlQDMFA8JYAkRWb7c-oB15UAkDpuBWJ5eLXgFkAM51-0AxgAAqQBAAC2sDAAFsFj7ECB1Aoe0EGNgAHk-AAI1cABHABVfxfAAt2IAAtJ1AdwR3xAwAGZAIccC0NnFhEAgnDB0ANiQ2dAGwkNcANcAAtQPTQABxDxBxDYA0Cg3c92PU9j1PEA7xXABJI90JfBckL3fclw3dDd0vfCbwfW8EALUB3VCUj31PJAACHZ0AP8CMP7MBABAWAA1U8nIAI3c3AXTYABvQDXGwTydP0gDyDAQBgB1fVADsHC8p1XQAQEBRJABtKzPLc9yADYAPctBPJ0gBWbzPIAZh80D3Kw7zPIADgc0D3KwmcCAGOdQF9FUVQKp9QLPYAYAATyAQtlL6UACJ0kBGz85oAAqQAyp1ALHstx2dVytPdDKstyzLsvq0CPO8nzquM0yzNAQoAF0yrSUjqsqqrXFqgBZNqopwTzPJALrXLsvrQB61rzMAwBWBx8iAABZMhyBYcgRwQBxFGAbBHAoABdAApAh6FwOAxEmvqgA)
100+
- [other answer](https://github.com/type-challenges/type-challenges/issues?q=label%3A612+label%3Aanswer)

0 commit comments

Comments
 (0)