DrillLab
练习Practice

动手做Get your hands on it

练习跟着课文走 —— 每节课尾都有本课的练习。这一页是全部练习的总库,想集中刷题的时候来。 每个练习都写清了它来自哪一节,卡住了就回去看那一节。Practice follows the lessons — every lesson ends with the exercises for that lesson. This page is the whole library, for when you want to drill in one sitting. Each exercise names the lesson it came from, so you can go back when you stall.

0 / 148个做对过you got right

练习Exercises

筛出 31 个练习(共 148 个) · 第 1 / 3 页。Showing 31 of 148 · page 1 / 3.
来自From package.json 逐字段读一遍package.json, field by field · 地基 · 项目与语言Foundations · project and language
L2填空Fill the blanks补全 subgraph 的 package.json 关键字段Fill in the key fields of the subgraph package.json

下面是 node-subgraph/package.json 的骨架,挖掉了三个决定项目行为的值。 照真实文件补回来。

Below is the skeleton of node-subgraph/package.json with three values removed. Each one decides how the project behaves. Put them back the way the real file has them.

JSONnode-subgraph/package.json3 个空3 blanks
1{
2 "name": "order-subgraph",
3 "main": "src/index.js",
4 "type": "",
5 "scripts": {
6 "start": "node src/index.js",
7 "test": "NODE_OPTIONS=--experimental-vm-modules "
8 },
9 "dependencies": {
10 "@apollo/server": "^4.10.0",
11 "@apollo/subgraph": "^2.7.0",
12 "graphql": "^16.8.1",
13 "graphql-tag": "^2.12.6",
14 "": "^2.2.2"
15 }
16}
把 3 个空都填上才能检查(还差 3 个)Fill all 3 blanks to check (3 to go)
来自From 数组与对象:不可变更新三件套Arrays and objects: three ways to update without changing the original · 地基 · 项目与语言Foundations · project and language
L2填空Fill the blanks补全 Q1 的三个数据操作Fill in the three data operations of Q1

这是 NoteManager 里三个 handler 的真实代码, 挖掉了决定行为的关键词。想清楚每个操作要「保留多少条」再填。

This is the real code of the three handlers in NoteManager, with the words that decide the behaviour removed. Before you fill each one in, work out how many items that operation has to keep.

TSXsrc/components/NoteManager/index.tsx4 个空4 blanks
1const handleSubmitNote = (submittedNote: Note) => {
2 if (noteToEdit) {
3 setNotes((prev) =>
4 prev.((note) =>
5 note.id === submittedNote.id ? submittedNote : note,
6 ),
7 );
8 setNoteToEdit(null);
9 } else {
10 setNotes((prev) => [, submittedNote]);
11 }
12};
13
14const handleDelete = (id: number) => {
15 setNotes((prev) => prev.((note) => note.id id));
16};
把 4 个空都填上才能检查(还差 4 个)Fill all 4 blanks to check (4 to go)
来自From 异步:Promise、await、all 和 allSettledAsync: Promise, await, all and allSettled · 地基 · 项目与语言Foundations · project and language
L2填空Fill the blanks补全 DataLoader 的批量函数Fill in the batch function of the DataLoader

这是 subgraph 里真实的 DataLoader 批量加载函数。 两个空都关系到「异步 + 数组」的固定套路。

This is the real DataLoader batch function from the subgraph. Both blanks are part of the fixed pattern for async work over an array.

JSsrc/resolvers/orderResolvers.js2 个空2 blanks
1function createShippingInfoLoader(shippingDataSource) {
2 return new DataLoader(async orderIds => {
3 const shippingInfos = await Promise.(
4 orderIds.(id => shippingDataSource.getShippingInfo(id))
5 );
6
7 return shippingInfos;
8 });
9}
把 2 个空都填上才能检查(还差 2 个)Fill all 2 blanks to check (2 to go)
来自From 类型、type 与 interfaceTypes, type and interface · 地基 · 项目与语言Foundations · project and language
L2填空Fill the blanks补全 NoteTable 的 props 类型Fill in the props type of NoteTable

这是 NoteTable 真实的 props 类型。 三个空:一个数组类型、一个函数类型的参数、一个函数类型的返回值。

This is the real props type of NoteTable. Three blanks: an array type, a parameter of a function type, and the return value of a function type.

TSXsrc/components/NoteTable/index.tsx3 个空3 blanks
1export interface NoteTableProps {
2 notes: ;
3 onDelete: (id: ) => void;
4 onEdit: (note: Note) => ;
5}
把 3 个空都填上才能检查(还差 3 个)Fill all 3 blanks to check (3 to go)
来自From 泛型参数,以及怎么读 tsc 的报错Generic parameters, and how to read a tsc error · 地基 · 项目与语言Foundations · project and language
L2填空Fill the blanks补全泛型参数Fill in the generic parameters

两处真实的泛型用法。想清楚「TypeScript 能不能自己推断出来」。

Two real uses of generics. For each one, work out whether TypeScript can infer it on its own.

TSX两个真实片段Two real snippets3 个空3 blanks
1// NoteManager:两个 state
2const [notes, setNotes] = useState<>([]);
3const [noteToEdit, setNoteToEdit] = useState<Note | >(null);
4
5// q2/taskRunner.ts:自定义泛型
6export type Task<T> = () => <T>;
把 3 个空都填上才能检查(还差 3 个)Fill all 3 blanks to check (3 to go)
来自From props:数据往下流,事件往上报props: data flows down, events go back up · React 考试React exam
L2填空Fill the blanks补全 NoteItem 的两个按钮Fill in the two buttons of NoteItem

这是 NoteItem 真实的两个按钮。 一个要传整条笔记,一个只传 id —— 想清楚各自要传什么, 以及怎么才能「点击时才执行」。

These are the two real buttons of NoteItem. One passes the whole note, the other passes only the id. Decide what each one has to pass, and how to make it run only on the click.

TSXsrc/components/NoteItem/index.tsx2 个空2 blanks
1<td>
2 <button onClick={ onEdit(note)} className="outlined">
3 Edit
4 </button>
5</td>
6<td>
7 <button onClick={() => onDelete()} className="danger">
8 Delete
9 </button>
10</td>
把 2 个空都填上才能检查(还差 2 个)Fill all 2 blanks to check (2 to go)
来自From 受控输入:value + onChange 的闭环Controlled inputs: the loop between value and onChange · React 考试React exam
L2填空Fill the blanks补全受控输入的闭环Complete the loop of a controlled input

NoteForm 里 textarea 那一段补全。 三个空构成一个完整的闭环。

Fill in the textarea part of NoteForm. The three blanks together form one complete loop.

TSXsrc/components/NoteForm/index.tsx3 个空3 blanks
1const [content, setContent] = ("");
2
3<textarea
4 placeholder="Content"
5 value={}
6 onChange={(e) => setContent()}
7 data-testid="form-textarea"
8 className="form-textarea"
9/>
把 3 个空都填上才能检查(还差 3 个)Fill all 3 blanks to check (3 to go)
来自From useEffect:把 props 的变化同步进 stateuseEffect: copying a change in props into state · React 考试React exam
L2填空Fill the blanks补全编辑回填的 useEffectComplete the useEffect that prefills the form for editing

这是 NoteForm 里那个决定 Task 3 成败的 effect。 两个空:一个分支条件,一个依赖数组。

This is the effect in NoteForm that decides whether Task 3 passes. Two blanks: one branch condition, one dependency array.

TSXsrc/components/NoteForm/index.tsx2 个空2 blanks
1useEffect(() => {
2 if () {
3 setTitle(noteToEdit.title);
4 setContent(noteToEdit.content);
5 } else {
6 setTitle("");
7 setContent("");
8 }
9}, );
把 2 个空都填上才能检查(还差 2 个)Fill all 2 blanks to check (2 to go)
来自From Task 1 · Add:提交表单,新笔记进入表格Task 1 · Add: submit the form and the new note appears in the table · React 考试React exam
L2填空Fill the blanks补全新增逻辑Fill in the add logic

两个空。想清楚「旧的要不要留」和「用哪种更新形式」。

Two blanks. Decide whether the old notes have to stay, and which form of update to use.

TSXsrc/components/NoteManager/index.tsx2 个空2 blanks
1const handleSubmitNote = (submittedNote: Note) => {
2 if (noteToEdit) {
3 // Task 3
4 } else {
5 setNotes(() => [, submittedNote]);
6 }
7};
把 2 个空都填上才能检查(还差 2 个)Fill all 2 blanks to check (2 to go)
来自From Task 2 · Delete:点 Delete,该行按 id 被移除Task 2 · Delete: click Delete and that one row is removed by id · React 考试React exam
L2填空Fill the blanks补全删除逻辑Fill in the delete logic

三个空。第三个空是这道题唯一会绕人的地方。

Three blanks. The third one is the only part that trips people up.

TSXsrc/components/NoteManager/index.tsx3 个空3 blanks
1const handleDelete = (id: number) => {
2 setNotes((prev) => prev.((note) => note. id));
3};
把 3 个空都填上才能检查(还差 3 个)Fill all 3 blanks to check (3 to go)
来自From Task 3 · Edit:回填、改文字、就地更新、退出编辑Task 3 · Edit: refill the form, change the button text, update the row where it is, leave edit mode · React 考试React exam
L2填空Fill the blanks补全编辑逻辑的四个关键位置Fill in the four key spots of the edit logic

四个空横跨两个函数。第 4 个空是最容易漏的那一行 —— 漏了它测试照样能过,但行为明显不对。

Four blanks across two functions. The fourth is the line people forget most often — without it the tests still pass, but the behavior is clearly wrong.

TSXsrc/components/NoteManager/index.tsx4 个空4 blanks
1const handleSubmitNote = (submittedNote: Note) => {
2 if (noteToEdit) {
3 setNotes((prev) =>
4 prev.((note) =>
5 note.id submittedNote.id ? : note,
6 ),
7 );
8 ;
9 } else {
10 setNotes((prev) => [...prev, submittedNote]);
11 }
12};
13
14const handleEdit = (note: Note) => {
15 setNoteToEdit(note);
16};
把 4 个空都填上才能检查(还差 4 个)Fill all 4 blanks to check (4 to go)
来自From 实现:worker pool(工人池)Building it: a worker pool, meaning a fixed number of workers sharing one queue · React 考试React exam
L2填空Fill the blanks补全 worker pool 的五个关键位置Fill in the five key spots of the worker pool

五个空。第 2 个和第 4 个是最容易写错的 —— 一个关系到「顺序」,一个关系到「任务到底有没有被启动」。

Five blanks. Numbers 2 and 4 are the ones most often written wrong: one decides the order, the other decides whether the task was started at all.

TSq2/taskRunner.ts5 个空5 blanks
1export async function runTasks<T>(
2 tasks: Task<T>[],
3 limit: number,
4): Promise<SettledResult<T>[]> {
5 const results: SettledResult<T>[] = new Array(tasks.length);
6 let nextIndex = 0;
7
8 const worker = async () => {
9 while (nextIndex tasks.length) {
10 const i = nextIndex;
11 nextIndex++;
12
13 try {
14 const value = await ;
15 results[] = { status: "fulfilled", value };
16 } catch (reason) {
17 results[i] = { status: "", reason };
18 }
19 }
20 };
21
22 const workerCount = Math.(limit, tasks.length);
23 const workers: Promise<void>[] = [];
24 for (let w = 0; w < workerCount; w++) {
25 workers.push(worker());
26 }
27 await Promise.all(workers);
28 return results;
29}
把 5 个空都填上才能检查(还差 5 个)Fill all 5 blanks to check (5 to go)