类型、type 与 interfaceTypes, type and interface
Note 和 NoteFormProps 这两个真实类型,把该讲的都讲全了。Two real types from the project, Note and NoteFormProps, cover everything you need here.
这一页有什么On this page5
- 会给变量、函数参数、返回值标类型Give a type to a variable, to a function parameter and to a return value
- 分清 type 和 interface 各自的场合(以及为什么这题里两个都用了)Know when type fits and when interface fits, and why this project uses both
- 会写可选字段、联合类型、函数类型Write an optional field, a union type and a function type
- 知道 strict: true 意味着什么Know what strict: true means
react-notes-app 是 strict 模式的 TypeScript 项目。props 类型写错、少写一个字段,构建就过不去。而两个考试的核心数据结构(Note、Order)都是从类型定义读起的。react-notes-app is a TypeScript project in strict mode. Get a props type wrong, or leave out one field, and the build fails. And in both exams the main data shapes, Note and Order, are read from their type definitions first.
react-notes-app/src/types/Note.ts整个 Q1 的数据形状The shape of all the Q1 data
react-notes-app/src/types/Note.tsreact-notes-app/src/components/NoteForm/index.tsxprops 类型的真实写法How the prop types are actually written
react-notes-app/src/components/NoteForm/index.tsxreact-notes-app/tsconfig.jsonstrict: true
react-notes-app/tsconfig.json从这个项目最重要的 3 行代码开始Start with the 3 most important lines in this project
整个 Q1 的数据结构就这么多。That is the whole data shape of Q1.
读一个陌生项目,先找类型定义。 它比任何 README 都准确 —— README 会过时,类型不会 (改了类型不匹配的代码,编译器立刻报错)。
这 3 行告诉了你几件关键的事:
id是number,不是 string。 所以后面比较要写note.id !== id, 而项目里生成 id 用的是Date.now()(返回数字)。- 三个字段都是必填(没有
?)。 所以你构造一个新 Note 时,三个都得给,少一个编译不过。 - 没有
createdAt、没有done—— 别自己加字段。
Reading an unfamiliar project, find the type definitions first. They beat any README for accuracy — a README goes stale, types do not (change code so it no longer matches a type and the compiler complains on the spot).
These 3 lines tell you several important things:
idis anumber, not a string. So comparisons later on readnote.id !== id, and the project generates ids withDate.now()(which returns a number).- All three fields are required (no
?). So when you build a new Note you have to supply all three; miss one and it will not compile. - No
createdAt, nodone— do not invent fields.
react-notes-app/src/types/Note.tstype 和 interface:这个项目里两个都用了type and interface: this project uses both
Note 用的是 type, 而 NoteFormProps 用的是 interface。 这不是随便选的,但也不是必须这么选 —— 大多数情况下两者可以互换。
type | interface | |
|---|---|---|
| 描述对象形状 | ✓ | ✓ |
联合类型 A | B | ✓ 只能用它 | ✗ |
| 同名重复声明会自动合并 | ✗ 报错 | ✓ 会合并 |
| 习惯用法 | 数据形状、联合、别名 | props、可能被扩展的公开契约 |
实用建议:照项目里已有的风格写。考试不会因为你用 type 还是 interface 扣分,但风格不一致会让人皱眉。 Q2 那边就必须用 type —— 因为SettledResult 是个联合类型,interface 做不到。
Note uses type, while NoteFormProps uses interface. That was not random, but it was not required either — most of the time the two are interchangeable.
type | interface | |
|---|---|---|
| Describe an object shape | ✓ | ✓ |
Union type A | B | ✓ the only option | ✗ |
| Two declarations of one name merge automatically | ✗ error | ✓ they merge |
| Conventional use | Data shapes, unions, aliases | Props, public contracts that may get extended |
Practical advice: write whatever style the project already uses. No exam docks points for type versus interface, but inconsistency makes people wince. Q2 has no choice but type — because SettledResult is a union, and interface cannot do that.
react-notes-app/src/components/NoteForm/index.tsxreact-notes-app/q2/taskRunner.tsstrict: true 意味着什么What strict: true means
react-notes-app/tsconfig.json 里写了"strict": true。它是一个开关包,一次打开好几项检查。 对你影响最大的两项:
strictNullChecks——null和undefined不再能随便赋给别的类型。 所以noteToEdit必须明确写成Note | null, 而且用它之前必须先判断。这就是为什么真实代码里到处是if (noteToEdit)。noImplicitAny—— 推断不出类型的参数不许留空。所以事件处理器要写(e: React.FormEvent<HTMLFormElement>), 不能光写(e)。
main.tsx 里那个 ! 就是 strictNullChecks 的产物:document.getElementById("root") 的类型是HTMLElement | null,而 createRoot不接受 null。! 是在说「我保证它不是 null」。
react-notes-app/tsconfig.json sets "strict": true. It is a bundle of switches that turns on several checks at once. The two that hit you hardest:
strictNullChecks—nullandundefinedcan no longer be handed to other types freely. SonoteToEdithas to be spelled out asNote | null, and you have to check it before using it. That is why the real code is full ofif (noteToEdit).noImplicitAny— a parameter whose type cannot be inferred may not be left bare. So the event handler is written(e: React.FormEvent<HTMLFormElement>), not just(e).
That ! in main.tsx is a product of strictNullChecks: document.getElementById("root") has type HTMLElement | null, and createRoot does not accept null. The ! is you saying “I guarantee this is not null”.
react-notes-app/src/main.tsx动手做Get your hands on it
填空只是过渡。真正掌握的标准,是在没有答案的时候从头写出来 —— 所以做完 L2 之后一定要往 L3、L4 走。Filling blanks is a stepping stone. The real bar is writing it from nothing, so once L2 is comfortable, push on to L3 and L4.
这是 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.
换一道题也能用Works on other problems too
考试不会原题重考。真正能带走的是「看到这种信号 → 伸手去拿这个解法」。The exam will not reuse the same question. What you take away is the reflex: see this signal, reach for that solution.
- 读项目先读类型定义:Note 的 3 行决定了 Q1 全部的数据操作。Read the type definitions first. The 3 lines of Note decide every data operation in Q1.
- type 和 interface 大多可互换;联合类型只能用 type。type and interface are interchangeable most of the time. Only type can express a union.
- (note: Note) => void 是函数类型;Note | null 是联合类型。(note: Note) => void is a function type. Note | null is a union type.
- strict: true 打开后,null 必须显式处理、参数必须有类型。With strict: true, null has to be handled explicitly and every parameter needs a type.
- ! 是非空断言,是你在替编译器担保,用错了运行时才炸。! is a non-null assertion. With it you tell the compiler that the value is not null, so it stops checking. If you are wrong, the failure appears only when the code runs.