|
1 | | -# 简单难度挑战 |
2 | | - |
3 | | -这些挑战适合TypeScript初学者,帮助你理解TypeScript的基本类型系统概念。 |
4 | | - |
5 | | -## 挑战列表 |
6 | | - |
7 | | -### 1. Pick<T, K> |
8 | | - |
9 | | -**要求**:实现 TypeScript 的 `Pick<T, K>` 工具类型。 |
10 | | - |
11 | | -**例子**: |
12 | | -```typescript |
13 | | -interface Todo { |
14 | | - title: string |
15 | | - description: string |
16 | | - completed: boolean |
17 | | -} |
| 1 | +--- |
| 2 | +title: 实现Readonly |
| 3 | +--- |
18 | 4 |
|
19 | | -type TodoPreview = MyPick<Todo, 'title' | 'completed'> |
20 | | -// 应该等于: { title: string; completed: boolean } |
21 | | -``` |
| 5 | +# {{ $frontmatter.title }} |
22 | 6 |
|
23 | | -**解决方案**: |
24 | | -```typescript |
25 | | -type MyPick<T, K extends keyof T> = { |
26 | | - [P in K]: T[P] |
27 | | -} |
28 | | -``` |
| 7 | +## 题目描述 |
29 | 8 |
|
30 | | -**解释**: |
31 | | -- `K extends keyof T` 确保 K 中的每个键都存在于 T 中 |
32 | | -- `[P in K]` 遍历 K 类型中的所有属性 |
33 | | -- `T[P]` 通过索引访问获取 T 中对应属性的类型 |
| 9 | +不要使用内置的 `Readonly<T>`,自己实现一个。 |
34 | 10 |
|
35 | | ---- |
| 11 | +该 `Readonly` 会接收一个 泛型参数,并返回一个完全一样的类型,只是所有属性都会被 `readonly` 所修饰。 |
36 | 12 |
|
37 | | -### 2. Readonly<T> |
| 13 | +也就是不可以再对该对象的属性赋值。 |
38 | 14 |
|
39 | | -**要求**:实现 TypeScript 的 `Readonly<T>` 工具类型。 |
| 15 | +例如: |
40 | 16 |
|
41 | | -**例子**: |
42 | | -```typescript |
| 17 | +```ts |
43 | 18 | interface Todo { |
44 | | - title: string |
45 | | - description: string |
| 19 | + title: string; |
| 20 | + description: string; |
46 | 21 | } |
47 | 22 |
|
48 | 23 | const todo: MyReadonly<Todo> = { |
49 | | - title: "Hey", |
50 | | - description: "foobar" |
51 | | -} |
| 24 | + title: 'Hey', |
| 25 | + description: 'foobar', |
| 26 | +}; |
52 | 27 |
|
53 | | -todo.title = "Hello" // 错误: 无法分配到 'title' 因为它是只读属性 |
54 | | -todo.description = "barFoo" // 错误: 无法分配到 'description' 因为它是只读属性 |
| 28 | +todo.title = 'Hello'; // Error: cannot reassign a readonly property |
| 29 | +todo.description = 'barFoo'; // Error: cannot reassign a readonly property |
55 | 30 | ``` |
56 | 31 |
|
57 | | -**解决方案**: |
58 | | -```typescript |
59 | | -type MyReadonly<T> = { |
60 | | - readonly [P in keyof T]: T[P] |
61 | | -} |
62 | | -``` |
63 | | -
|
64 | | -**解释**: |
65 | | -- `[P in keyof T]` 遍历 T 类型中的所有属性 |
66 | | -- `readonly` 修饰符使所有属性变为只读 |
67 | | -- `T[P]` 保持原有属性的类型不变 |
68 | | -
|
69 | | ---- |
70 | | -
|
71 | | -### 3. Tuple to Object |
72 | | -
|
73 | | -**要求**:给定一个元组类型,将它转换为对象类型,其属性键为元组元素的字面量类型,属性值为对应元素类型。 |
| 32 | +## 分析 |
74 | 33 |
|
75 | | -**例子**: |
76 | | -```typescript |
77 | | -const tuple = ['tesla', 'model 3', 'model X', 'model Y'] as const |
| 34 | +这一题,本质也是对对象类型进行遍历,然后为每一个属性增加 `readonly` 的修饰符,只需要在遍历的时候为每一个属性增加只读修饰符。 |
78 | 35 |
|
79 | | -type Result = TupleToObject<typeof tuple> |
80 | | -// 预期结果: { tesla: 'tesla', 'model 3': 'model 3', 'model X': 'model X', 'model Y': 'model Y' } |
81 | | -``` |
82 | | -
|
83 | | -**解决方案**: |
84 | | -```typescript |
85 | | -type TupleToObject<T extends readonly any[]> = { |
86 | | - [P in T[number]]: P |
87 | | -} |
| 36 | +```ts |
| 37 | +type MyReadonly<T> = { |
| 38 | + readonly [P in keyof T]: T[P]; |
| 39 | +}; |
88 | 40 | ``` |
89 | 41 |
|
90 | | -**解释**: |
91 | | -- `T extends readonly any[]` 约束输入类型必须是只读元组/数组 |
92 | | -- `T[number]` 获取元组中所有元素的联合类型 |
93 | | -- `[P in T[number]]: P` 遍历这个联合类型,将每个元素作为键和值创建对象属性 |
| 42 | +## 题解 |
94 | 43 |
|
95 | | ---- |
| 44 | +```ts |
| 45 | +type MyReadonly<T> = { |
| 46 | + readonly [P in keyof T]: T[P]; |
| 47 | +}; |
| 48 | +``` |
96 | 49 |
|
97 | | -我们会不断添加更多简单难度的挑战,请定期查看更新! |
| 50 | +## 知识点 |
98 | 51 |
|
99 | | -[返回挑战列表](/challenges/) |
| 52 | +1. `[P in keyof T]` 遍历 对象类型(数组也是对象) |
| 53 | +2. `readonly` 增加修饰符即可 |
0 commit comments