泛型参数,以及怎么读 tsc 的报错Generic parameters, and how to read a tsc error
useState<Note[]> 那对尖括号在说什么,和 react-notes-app 那 10 个构建错误的真相。What the angle brackets in useState<Note[]> say, and the real cause of the 10 build errors in react-notes-app.
这一页有什么On this page6
- 看懂 useState<Note[]>([]) 和 Task<T> 里的尖括号Read the angle brackets in useState<Note[]>([]) and in Task<T>
- 会读 tsc 报错的四个部分:文件、位置、错误码、说明Read the four parts of a tsc error: file, position, error code, explanation
- 能分辨「我的代码错了」和「项目配置本身有问题」Tell the difference between a mistake in your code and a problem in the project setup
- 知道常见错误码 TS2304 / TS2582 / TS2345 各是什么意思Know what the common codes TS2304, TS2582 and TS2345 each mean
react-notes-app 的 npm run build 在原始状态下就是失败的 —— 10 个 tsc 错误,全部来自测试文件的类型配置缺失。能不能认出「这不是我的问题」,直接决定你会不会浪费半小时。In react-notes-app, npm run build fails as delivered. All 10 tsc errors come from missing type settings for the test files. Recognising that the fault is not yours is what decides whether you lose half an hour.
react-notes-app/tsconfig.jsoninclude 了 src,但没配 vitest 全局类型It includes src but does not configure the vitest global types
react-notes-app/tsconfig.jsonreact-notes-app/src/NoteManager.test.tsx报错就出在这个文件This is the file the error comes from
react-notes-app/src/NoteManager.test.tsx尖括号:告诉泛型「这次装的是什么」Angle brackets: telling a generic what it holds this time
泛型(generic)就是一个「留了洞的类型」,调用的人负责填。A generic is a type with a hole left in it. Whoever calls it fills the hole.
useState 是 React 提供的函数,它不可能知道你要存什么 —— 可能是数字、可能是字符串、可能是笔记数组。 所以它的类型定义留了一个洞,写成 useState<S>。 你调用时用尖括号把洞填上:
为什么第一个必须显式写 <Note[]>? 因为初始值是 [] —— 一个空数组, TypeScript 从它身上只能推断出「某种数组」,不知道装什么。 不写的话后面 setNotes([...prev, note]) 就会报类型错。
而第三个 useState("") 不用写, 因为初始值 "" 已经把类型说清楚了:string。规则:推断得出来就别写,推断不出来才写。
useState is a function React hands you, and it has no way of knowing what you plan to store — a number, a string, an array of notes. So its type definition leaves a hole in it, written useState<S>. You fill the hole with angle brackets when you call it:
Why does the first one have to spell out <Note[]>? Because the initial value is [] — an empty array, and all TypeScript can infer from it is “some kind of array”, with no idea what goes in. Leave it off and setNotes([...prev, note]) later throws a type error.
The third one, useState(""), needs nothing, because the initial value "" has already settled the type: string. The rule: if it can be inferred, do not write it; write it only when it cannot.
react-notes-app/src/components/NoteManager/index.tsx 与 NoteForm/index.tsxreact-notes-app/q2/taskRunner.tstsc 报错的四个部分The four parts of a tsc error
拿一条真实的报错拆开看:
- 文件
src/NoteManager.test.tsx—— 哪个文件 - 位置
(5,1)—— 第 5 行第 1 列 - 错误码
TS2582—— 可以直接搜的编号 - 说明 —— 人话描述,而且这条还带了修复建议
永远从第一条错误看起。TypeScript 的报错常常会连锁: 一个类型错了,后面十处用到它的地方全跟着报。修掉第一条, 后面九条可能自己就没了。
Take one real error apart:
- File
src/NoteManager.test.tsx— which file - Position
(5,1)— line 5, column 1 - Error code
TS2582— a number you can search directly - Message — a plain-language description, and this one even suggests a fix
Always start from the first error. TypeScript errors chain constantly: one type goes wrong, and the ten places that use it all report too. Fix the first one and the other nine may disappear by themselves.
实测:这 10 个错误不是你写的代码的问题Tried for real: these 10 errors are not caused by the code you wrote
这是 react-notes-app 自带的配置缺陷。认出它,别去改业务代码。It is a setup defect that ships with react-notes-app. Recognise it, and leave your own code alone.
看清三件事,就能确定「不是我的问题」:
- 报错全在测试文件里,一条都不在
src/components/下。 - 报的是
test和expect找不到 —— 这两个不是你写的,是测试框架注入的全局变量。 npx vitest run实测 4 个测试全过。也就是说代码逻辑完全正确,只是 tsc 不认识这两个全局名字。
根因:tsconfig.json 的include: ["src", "q2"]把测试文件也纳入了类型检查,但没有任何地方告诉 tsc 「这些全局变量存在」。缺的是"types": ["vitest/globals"](或者在测试文件里显式 import)。
考场上该怎么办?npm run build 失败但 npx vitest run 全过时, 先确认失败发生在 tsc 那一步、而且只涉及测试文件的全局名字。 确认之后:继续用 vitest 验证你的实现,并在提交说明里点出这个配置问题。把它当成一个观察记下来,而不是当成一个要你修的任务 —— 题目没有要求你改配置,而擅自改 tsconfig 有可能影响判卷。
Three things, once you see them clearly, settle that this is not your problem:
- Every error is in the test file, not one of them under
src/components/. - What it cannot find is
testandexpect— you did not write those two; the test framework injects them as globals. npx vitest runpasses all 4 tests, measured. Which means the code logic is entirely correct and tsc simply does not know those two global names.
Root cause: the include: ["src", "q2"] in tsconfig.json pulls the test file into type checking, but nothing anywhere tells tsc that those globals exist. What is missing is "types": ["vitest/globals"] (or an explicit import inside the test file).
What should you do in the exam? When npm run build fails but npx vitest run passes, first confirm the failure happens at the tsc step and only involves global names from the test file. Once confirmed: keep using vitest to verify your implementation, and point out the config problem in your submission notes. Record it as an observation, not as a task you were asked to fix — nothing in the question asks you to change config, and editing tsconfig on your own initiative could affect grading.
react-notes-app/tsconfig.json几个会真的遇到的错误码The error codes you will actually meet
| 错误码 | 意思 | 通常的原因 |
|---|---|---|
TS2304 | Cannot find name 'X' | 名字打错、没 import、或者缺全局类型声明 |
TS2582 | Cannot find name 'test' | 2304 的特化版,专门提示你缺测试框架类型 |
TS2345 | 参数类型不匹配 | 传了 string 给要 number 的参数(比如 id 类型搞混) |
TS2339 | 属性不存在 | 拼错字段名,或者对象类型不是你以为的那个 |
TS2531 / TS18047 | 可能是 null | strictNullChecks:用之前没判断 |
TS7006 | 参数隐式为 any | noImplicitAny:回调参数没写类型 |
| Code | Meaning | Usual cause |
|---|---|---|
TS2304 | Cannot find name 'X' | Typo in the name, no import, or a missing global type declaration |
TS2582 | Cannot find name 'test' | The specialised form of 2304, telling you the test framework types are missing |
TS2345 | Argument type mismatch | Passed a string where a number was wanted (mixing up an id type, say) |
TS2339 | Property does not exist | Misspelled field name, or the object is not the type you assumed |
TS2531 / TS18047 | Possibly null | strictNullChecks: you did not check before using it |
TS7006 | Parameter implicitly has an any type | noImplicitAny: the callback parameter has no type written |
动手做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.
你刚 clone 好 react-notes-app,一行代码都还没写,先跑了npm run build,得到 10 个TS2582: Cannot find name 'test'。 同时 npx vitest run 显示 4 个测试全过。 最合理的判断是?
You have just cloned react-notes-app, written not one line of code, and run npm run build. You get 10 of TS2582: Cannot find name 'test'. At the same time npx vitest run shows all 4 tests passing. What is the most sensible conclusion?
两处真实的泛型用法。想清楚「TypeScript 能不能自己推断出来」。
Two real uses of generics. For each one, work out whether TypeScript can infer it on its own.
换一道题也能用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.
- 泛型是「留洞的类型」,尖括号是你在填洞。A generic is a type with a hole in it. The angle brackets are you filling the hole.
- 初始值看不出类型(空数组、null)时必须显式写泛型参数。When the starting value shows no type, as with an empty array or null, write the generic parameter yourself.
- tsc 报错四件套:文件、行列、错误码、说明。永远先看第一条。A tsc error has four parts: file, line and column, error code, explanation. Always read the first error first.
- react-notes-app 的 npm run build 原生失败,10 个错全在测试文件,与你的实现无关。npm run build fails in react-notes-app as delivered. All 10 errors are in test files and have nothing to do with your work.
- 分辨「我的错」和「项目的错」:看报错位置、报的是谁的名字、测试跑不跑得过。To tell your own mistake from a project defect, look at where the error points, whose name it complains about, and whether the tests still pass.