Skip to content

Commit eab96ca

Browse files
💄 文档样式修改
1 parent 43e8701 commit eab96ca

30 files changed

+89
-623
lines changed

docs/challenges/medium/Absolute.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ title: 实现Absolute
44

55
# {{ $frontmatter.title }}
66

7-
## 题目描述
7+
## 🎯 题目描述
88

99
实现一个接收 string,number 或 bigInt 类型参数的`Absolute`类型,返回一个正数字符串。
1010

@@ -15,7 +15,7 @@ type Test = -100;
1515
type Result = Absolute<Test>; // expected to be "100"
1616
```
1717

18-
## 分析
18+
## 🔍 分析
1919

2020
这个题本质也是字符的推断匹配,但是由于入参是 number 类型的,所以在进行推断匹配前需要进行一次转化,对于 ts 来讲,也非常简单:
2121

@@ -28,7 +28,7 @@ type Case1 = NumberToString<100>;
2828

2929
转换成字符后,可以直接进行 `-` 号的匹配,有 `-` 号,就只保留剩余的字符,否则全部保留即可。
3030

31-
## 题解
31+
## 🛠️ 题解
3232

3333
```ts
3434
type Absolute<T extends number | string | bigint> = `${T}` extends `-${infer S}`
@@ -38,7 +38,7 @@ type Absolute<T extends number | string | bigint> = `${T}` extends `-${infer S}`
3838
`${T}`;
3939
```
4040

41-
## 知识点
41+
## 💡 知识点
4242

4343
1. number 转 string
4444
2. 字符推断匹配套路: `` A extends `-${infer R}` ``

docs/challenges/medium/AnyOf.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ title: AnyOf
44

55
# {{ $frontmatter.title }}
66

7-
## 题目描述
7+
## 🎯 题目描述
88

99
在类型系统中实现类似于 Python 中 `any` 函数。类型接收一个数组,如果数组中任一个元素为真,则返回 `true`,否则返回 `false`。如果数组为空,返回 `false`
1010

@@ -15,7 +15,7 @@ type Sample1 = AnyOf<[1, '', false, [], {}]>; // expected to be true.
1515
type Sample2 = AnyOf<[0, '', false, [], {}]>; // expected to be false.
1616
```
1717

18-
## 分析
18+
## 🔍 分析
1919

2020
这个题目看起来只需要遍历一次元组,遇到 false 元素,就继续递归判断剩余元素,否则就返回 true,直到遍历结束,那么就返回 false。
2121

@@ -25,7 +25,7 @@ type Sample2 = AnyOf<[0, '', false, [], {}]>; // expected to be false.
2525

2626
可以通过定义一个 Zerolist 的类型,`A extends Zerolist` 就简单认为这个元素是 false。
2727

28-
## 题解
28+
## 🛠️ 题解
2929

3030
```ts
3131
export type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends <
@@ -46,6 +46,6 @@ type AnyOf<T extends readonly any[]> = T extends [infer F, ...infer R]
4646
: false;
4747
```
4848

49-
## 知识点
49+
## 💡 知识点
5050

5151
1. `[] | Function | { a: any } extends {}` 为 true

docs/challenges/medium/AppendToObject.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ title: AppendToObject
44

55
# {{ $frontmatter.title }}
66

7-
## 题目描述
7+
## 🎯 题目描述
88

99
实现一个为接口添加一个新字段的类型。该类型接收三个参数,返回带有新字段的接口类型。
1010

@@ -15,11 +15,11 @@ type Test = { id: '1' };
1515
type Result = AppendToObject<Test, 'value', 4>; // expected to be { id: '1', value: 4 }
1616
```
1717

18-
## 分析
18+
## 🔍 分析
1919

20-
这题操作的类型时对象,在对象上新增属性,相比较之前的 [实现 Omit](/medium/实现Omit.md) 要简单很多,只需要根据传入的参数生成新的类型,同当前类型交叉即可得到结果。
20+
这题操作的类型时对象,在对象上新增属性,相比较之前的 [实现 Omit](./Omit.md) 要简单很多,只需要根据传入的参数生成新的类型,同当前类型交叉即可得到结果。
2121

22-
## 题解
22+
## 🛠️ 题解
2323

2424
```ts
2525
type Merge<T> = {
@@ -66,7 +66,7 @@ type Case1 = Equal<A, B> extends true ? true : false;
6666
type Case2 = Equal<A, Merge<B>> extends true ? true : false;
6767
```
6868

69-
## 知识点
69+
## 💡 知识点
7070

7171
1. 对象交叉
7272
2. 交叉后的对象 Merge

docs/challenges/medium/Capitalize.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ title: 实现Capitalize
44

55
# {{ $frontmatter.title }}
66

7-
## 题目描述
7+
## 🎯 题目描述
88

99
实现 `Capitalize<T>` 它将字符串的第一个字母转换为大写,其余字母保持原样。
1010

@@ -14,22 +14,22 @@ title: 实现Capitalize
1414
type capitalized = Capitalize<'hello world'>; // expected to be 'Hello world'
1515
```
1616

17-
## 分析
17+
## 🔍 分析
1818

1919
思路其实比较简单,就是找到第一个字符,大写之后和其余字符拼接即可。
2020

2121
这里值得一提的是 ts 本身自带这个方法,可以参考 官方文档 `uppercasestringtype`,但是其定义的地方是 intrinsic,我们看不到。
2222

2323
同时 Ts 还自带了大写整个字符的方法 Uppercase, 想要实现本题目,可以通过推断匹配的方式选出第一个字符后,大写该字符,并和原字符拼接即可。
2424

25-
## 题解
25+
## 🛠️ 题解
2626

2727
```ts
2828
type MyCapitalize<S extends string> = S extends `${infer F}${infer R}`
2929
? `${Uppercase<F>}${R}`
3030
: '';
3131
```
3232

33-
## 知识点
33+
## 💡 知识点
3434

3535
1. 字符串推断匹配: `` A extends `${infer F}${infer R}` ``

docs/challenges/medium/DeepReadonly.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ title: 实现DeepReadonly
44

55
# {{ $frontmatter.title }}
66

7-
## 题目描述
7+
## 🎯 题目描述
88

99
实现一个通用的`DeepReadonly<T>`,它将对象的每个参数及其子对象递归地设为只读。
1010

@@ -32,7 +32,7 @@ type Expected = {
3232
type Todo = DeepReadonly<X>; // should be same as `Expected`
3333
```
3434

35-
## 分析
35+
## 🔍 分析
3636

3737
```ts
3838
type DeepReadonly<T> = {
@@ -79,7 +79,7 @@ type Case5 = keyof (() => {});
7979

8080
所以对于此题,只需要增加函数的额外处理即可。
8181

82-
## 题解
82+
## 🛠️ 题解
8383

8484
```ts
8585
type DeepReadonly<T> = {
@@ -93,7 +93,7 @@ type DeepReadonly<T> = {
9393

9494
增加函数的场景判断即可。
9595

96-
## 知识点
96+
## 💡 知识点
9797

9898
1. 递归处理嵌套问题
9999
2. 元组可以使用遍历对象的方法进行遍历

docs/challenges/medium/Diff.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ title: 实现Diff
44

55
# {{ $frontmatter.title }}
66

7-
## 题目描述
7+
## 🎯 题目描述
88

99
获取两个接口类型中的差值属性。
1010

@@ -22,13 +22,13 @@ type Result1 = Diff<Foo, Bar>; // { b: number, c: boolean }
2222
type Result2 = Diff<Bar, Foo>; // { b: number, c: boolean }
2323
```
2424

25-
## 分析
25+
## 🔍 分析
2626

2727
这道题目其实就比较宽泛了,获取只存在于 A 或 只存在于 B 中的属性,网上有很多借助 `Omit`, `Exclude`, `&` 的解法,我认为都不太直观,其实借助 `as` 非常好实现。关于 `as` 可以参考 [实现 Omit](/medium/实现Omit.md) 中介绍的部分。
2828

2929
首先通过 `keyof A | keyof B` 可以获取所有的属性,接下来只需要让即存在于 A 中的属性 又存在于 B 中的属性为 never 即可去除该属性,也就是 `P extends keyof A & keyof B ? never : P`。讲到这里题解基本就出来了。
3030

31-
## 题解
31+
## 🛠️ 题解
3232

3333
```ts
3434
type Diff<O, O1> = {
@@ -39,6 +39,6 @@ type Diff<O, O1> = {
3939
};
4040
```
4141

42-
## 知识点
42+
## 💡 知识点
4343

4444
1.[实现 Omit](/medium/实现Omit.md)

docs/challenges/medium/Flatten.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ title: 实现Flatten
44

55
# {{ $frontmatter.title }}
66

7-
## 题目描述
7+
## 🎯 题目描述
88

99
在这个挑战中,你需要写一个接受数组的类型,并且返回扁平化的数组类型。
1010

@@ -14,13 +14,13 @@ title: 实现Flatten
1414
type flatten = Flatten<[1, 2, [3, 4], [[[5]]]]>; // [1, 2, 3, 4, 5]
1515
```
1616

17-
## 分析
17+
## 🔍 分析
1818

1919
这题又回到了元组,flatten 的逻辑本身也比较简单,就是遍历元组,当元素还是元组时,继续递归处理,直到元素非元组结束。
2020

2121
元组的遍历方法可以通过匹配推断:`A extends [infer F, ...infer R]`
2222

23-
## 题解
23+
## 🛠️ 题解
2424

2525
```ts
2626
type Flatten<T> =
@@ -40,7 +40,7 @@ type Flatten<T> =
4040

4141
同时可以留意下最后的 空元组,不理解的可以查看 [实现 Pop](/medium/实现Pop.md) 中提到的边界条件。
4242

43-
## 知识点
43+
## 💡 知识点
4444

4545
1. 元组遍历套路: `T extends [infer F, ...infer R]`
4646
2. 元组遍历边界条件:推断的类型有两个,当入参没有元素时,会走 false 逻辑

docs/challenges/medium/KebabCase.md

Lines changed: 0 additions & 63 deletions
This file was deleted.

docs/challenges/medium/Merge.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ title: 实现Merge
44

55
# {{ $frontmatter.title }}
66

7-
## 题目描述
7+
## 🎯 题目描述
88

99
将两个类型合并成一个类型,第二个类型的键会覆盖第一个类型的键。
1010

@@ -24,7 +24,7 @@ type coo = {
2424
type Result = Merge<foo, coo>; // expected to be {name: string, age: number, sex: string}
2525
```
2626

27-
## 分析
27+
## 🔍 分析
2828

2929
这个题如果不要求后者同名属性覆盖前者的话,直接交叉即可解决问题。
3030

@@ -48,7 +48,7 @@ type Merge<T, S> = {
4848

4949
还有没有其他思路?其实也有,就是不借助交叉,直接遍历 `keyof T | keyof S`,然后在取值的时候先取后者的类型即可。可以直接看题解。
5050

51-
## 题解
51+
## 🛠️ 题解
5252

5353
```ts
5454
type Merge<F, S> = {
@@ -65,6 +65,6 @@ type Merge<F, S> = {
6565
};
6666
```
6767

68-
## 知识点
68+
## 💡 知识点
6969

7070
1.[实现 Omit](/medium/实现Omit.md)

docs/challenges/medium/Omit.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ title: 实现Omit
44

55
# {{ $frontmatter.title }}
66

7-
## 题目描述
7+
## 🎯 题目描述
88

99
不使用 `Omit` 实现 TypeScript 的 `Omit<T, K>` 泛型。
1010

@@ -26,7 +26,7 @@ const todo: TodoPreview = {
2626
};
2727
```
2828

29-
## 分析
29+
## 🔍 分析
3030

3131
Omit 是 ts 自带的一个工具类,其原本的内部实现如下:
3232

@@ -76,7 +76,7 @@ type Case1 = Copy<{ a: 1; b: 2 }>;
7676

7777
通过强制声明键值为 never,其结果就是该键值就会被忽略掉。到这一步了,题解也呼之欲出,只需要判断当前键值是否是目标键值的一员,如果是,就忽略掉。
7878

79-
## 题解
79+
## 🛠️ 题解
8080

8181
```ts
8282
type MyOmit<T, K extends keyof T> = {
@@ -86,7 +86,7 @@ type MyOmit<T, K extends keyof T> = {
8686

8787
其核心就是利用 `as` 强制转换键值类型,又借助条件表达式将符合条件的键值改为 never,从而达到目标。
8888

89-
## 知识点
89+
## 💡 知识点
9090

9191
1. 对象遍历的方式: `{ [P in keyof T]: T[P] }`
9292
2. `as` 表达式在对象遍历时的用途

0 commit comments

Comments
 (0)