数组、元组与函数类型 — 第一批复合类型
数组、元组与函数类型 — 第一批复合类型
这一章讲三件事: 「一篮子同类型的东西」怎么描述(数组、元组); 「给函数传一个类型当参数」是怎么回事(Set、Map,以及谁不配收); 以及函数自己的类型怎么写全——从可选参数到 async 的 Promise。 读完你会写出完整的函数签名,并第一次碰到「类型信仰 vs 类型安全」这条全书反复出现的分界线。
1. 顶层全景
复合类型两大家族:
「同类型的篮子」—— 数组 string[] / Array<string>
「固定座位的篮子」—— 元组 [string, number]
函数三件事:
参数怎么标(可选 ?、默认 =、rest ...)→ 返回值怎么标(: string)
→ 函数本身作为一种类型怎么写((item: string) => number)
图说:下半张图(函数)是本章的重头;上半张(数组/元组)是它的铺垫。2. 数组:两种写法,一个意思
解决什么问题: 一个数组里装着许多同类型的元素,怎么标注?
第一种写法,方括号缀在元素类型后面:
let albums: string[] = ["Rubber Soul", "Revolver", "Sgt. Pepper"];
let dates: number[] = [1965, 1966, 1967];第二种写法,用 Array 类型加尖括号,把元素类型当参数传进去:
let albums: Array<string> = ["Rubber Soul", "Revolver", "Sgt. Pepper"];两种写法完全等价。日常用方括号,理由有二:更短;而且 TypeScript 报错时用的就是方括号形式, 和你看到的信息保持一致1。 但尖括号形式要眼熟——它马上会在元组之外的战场上反复出现(本章第 4 节,以及第 16 章的泛型)。
数组装对象,有两种摆法。内联写:
type ArrayOfAlbums = {artist: string; title: string; year: number}[];或者先起别名再包一层:
type Album = {artist: string; title: string; year: number};
type ArrayOfAlbums = Album[]; // 或 Array<Album>装错了会当场被抓:往 Album[] 里 push 一个 {name: "Karma", type: "cat"},
报错 Argument of type '{name...}' is not assignable to parameter of type 'Album'2。
原书对摆法有一个明确的偏好,值得单独记住:内联写法能用,但更倾向抽出一个新类型——
因为应用的另一个地方很可能也要用 Ingredient(配料)这个类型3。
这和第 04 章「类型别名 = 单一事实源」是同一条原则在复合类型上的复用。
3. 元组:座位固定的数组
解决什么问题: 有的「篮子」不是「随便多少个同一种东西」,而是固定几个位置、各坐各的类型。 比如「一张唱片 + 它的播放量」想绑在一起,又不想专门为它建一个类型。
// 元组:恰好两个元素,第一个是 string,第二个是 number
let album: [string, number] = ["Rubber Soul", 1965];
// 数组:随便多少个 string
let albums: string[] = ["Rubber Soul", "Revolver"];对比着看:方括号贴着变量名(string[])= 任意长度的数组;
方括号里装着类型([string, number])= 固定座位的元组4。
取值和普通数组一样:albumWithPlayCount[0] 是 Album,[1] 是播放量5。
练习里还有一个好看的用法——可选座位:经纬度坐标里高度可以不给
const goToLocation = (
coordinates: [latitude: number, longitude: number, elevation?: number],
) => {};elevation? 的意思是「第三个位置可以有,可以没有」;没有时取到的是 number | undefined6。
命名元组是给座位挂牌子:
type MyTuple = [album: Album, playCount: number];纯粹为了人读得更好;这些名字运行时不存在,只是说明每个位置该放什么的描述7。
练习的对照很直观:坐标元组 [x: number, y: number] 比裸的 [number, number] 一眼能懂8。
4. 给函数传类型:Set、Map,与判定法
先停一步看一个已经在用的语法。Array<string> 其实是把一个类型(string)当参数传给另一个类型(Array)9。
尖括号 < > 就是「类型参数」的传递通道——而且函数也能收类型参数。
Set:三种活法
解决什么问题: Set 是 JavaScript 里「不重复值的集合」。空着手 new 一个会怎样?
const formats = new Set();
// 悬停 → const formats: Set<unknown>unknown 在这里先只当「不知道」理解(第 06 章细讲):Set 不知道你要装什么,只好说不知道10。
三种解法:
- 创建时就放值:
new Set(["CD", "DVD"])→ 推断出Set<string>11; - 创建后传类型:
new Set<string>()→ 空集合,但声明只装字符串;此后formats.add(8)当场红线12; - 想要别的元素类型就换别的参数。
原书对这一步的定性是:「你可以给函数传值,也可以给函数传类型」——这是 TypeScript 里极其要紧的一件事13。
Map:两个类型参数
Map 是字典(键到值的映射),要收两个类型参数:
type User = {name: string; age: number};
const userMap = new Map<number, User>();
userMap.set(1, {name: "Max", age: 30}); // 可以
userMap.set("3", {name: "Anna", age: 29}); // 红线:键必须是 number加上类型参数之前,悬停显示的是 Map<any, any>——什么键什么值都放行,检查等于没有14。
判定法:谁能收类型参数?
解决什么问题: 你想给 document.getElementById 传个类型,说「我要的是音频元素」——报错。
const audioElement = document.getElementById<HTMLAudioElement>("player");
// 红线:Expected 0 type arguments, but got 1.原书的判定法简单到可爱:悬停那个函数,看它的签名里有没有尖括号。
getElementById 悬停:
(method) Document.getElementById(elementId: string): HTMLElement | null
——没有尖括号 → 不能传类型参数
querySelector 悬停:
(method) ParentNode.querySelector<Element>(selectors: string): Element | null
——有 <Element> → 能传,于是:
document.querySelector<HTMLAudioElement>("#player") ✅「大多数函数收不了类型参数」——这句话原书是当标题写的16。 能收的是少数被专门设计成泛型的函数(第 17 章教你自己写)。
JSON.parse:能收类型参数的反面教材
把 JSON 字符串解析成对象,人人都想:JSON.parse<我的类型>(...)——报错:Expected 0 type arguments17。
悬停它的签名:JSON.parse(text: string, ...): any——它永远返回 any18。
绕法是给变量标注:
const parsedData: {name: string; age: number} = JSON.parse('{"name": "Alice"}');为什么能过?因为 any 关掉了检查,任何类型都接得住19。但这正是危险所在——
你标成 number 它也不拦你。原书给这种做法起了个名:「type faith(类型信仰)」而不是「type safe(类型安全)」——
你在祈祷数据真是那个形状,而且要靠自己让标注和真实数据保持一致20。
判断(我们的,不是书里的): 这句「type faith vs type safe」是全书前四章最有价值的一句警示, 它点破了静态类型系统的能力边界:类型检查只在你告诉它的范围内有效。 凡是数据来自运行时的边界(JSON、网络响应、表单),标注的强弱不改变命运—— 想要真安全,得在边界上做运行时校验(本书不展开;这是 schema 校验库的地盘)。 如果错,会错在: 对完全可信的内部数据(比如刚被自己序列化的配置), type faith 的代价确实接近零,这条警示对那些场景是过度紧张。
5. 函数参数的最后几块拼图
回到第 04 章的 logAlbumInfo,把它的签名补完整。
可选参数(?,前面对象属性见过的记号):
const logAlbumInfo = (
title: string,
trackCount: number,
isReleased: boolean,
releaseDate?: string, // 可以不给
) => {};悬停 releaseDate,类型是 string | undefined——第四个参数「可能是字符串,可能没给」21。
默认参数(=):不给时用一个兜底值。format = "CD"——
而且这里 : string 可以省:TypeScript 从默认值 "CD" 推断出它是字符串22。
有一个易错点,练习里专门考了:? 和 = 不能同时用。
last?: string = "Pocock" 报错 Parameter cannot have question mark and initializer——
有默认值就意味着「可以不传」,可选性已经隐含了,再问一次就是废话23。
rest 参数(...):「后面还跟任意多个字符串」。
function getAlbumFormats(album: Album, ...formats: string[]) { /* ... */ }
getAlbumFormats({artist: "Radiohead", title: "OK Computer", year: 1997},
"CD", "LP", "Cassette");不传类型的话报错 Rest parameter 'strings' implicitly has an 'any[]' type24——
rest 收集成一个数组,所以给它数组类型。
6. 返回值标注与函数类型
返回值标在参数列表的右括号后面:
const logAlbumInfo = (title: string, trackCount: number, isReleased: boolean): string => {
return 123; // 红线:Type 'number' is not assignable to type 'string'.
};原书的用法定位:想强制「必须返回某种值」时才标25——日常让推断代劳(第 04 章)。
函数类型——把「函数」本身当一种类型来描述,写法是箭头函数的样子去掉函数体:
type Mapper = (item: string) => number;读法:「一个函数,收一个 string 参数,返回 number」。 用在给回调参数定型:
const mapOverItems = (items: string[], map: (item: string) => number) => {
return items.map(map);
};练习里那个「三级进化」值得走一遍:makeChange 参数先标 () => any →
报错说「你声明它收 0 个参数,却传了 1 个」→ 改成 (user: User) => any →
再收紧成 (user: User) => User——此时回调体里写 name: 123 会被当场拦下,
写属性还有补全26。函数类型里同样可以写可选参数、rest 参数、多参数27。
7. void:「这个返回值请忽略」
解决什么问题: 有的函数做事不产出值,比如 console.log。悬停 .log:
(method) Console.log(...data: any[]): voidvoid 是 TypeScript 的专用词,意思是「这个返回值应当被有意忽略」28。
什么时候要用它而不是 undefined?练习的对照干净利落:
const acceptsCallback = (callback: () => undefined) => { callback(); };
const returnString = () => { return "Hello!"; };
acceptsCallback(returnString); // 红线!
// Argument of type '() => string' is not assignable to parameter of type '() => undefined'.把参数类型换成 () => void,红线消失——void 的妙处:比较时忽略返回值。
「有返回值的函数」可以放进「声明返回值会被忽略」的槽位;但「声明返回 undefined」的槽位,
你返回字符串就不行29。记一条实用规则:不关心结果的回调,一律标 () => void30。
(注意:第 06 章会看到,JavaScript 里「函数没写 return」实际返回 undefined——
void 和 undefined 在类型层面是刻意分开的两张面孔。)
8. async 函数:必须返回 Promise
异步函数想标返回 User?TypeScript 的报错直接给了答案:
The return type of an async function or method must be the global Promise type.
Did you mean to write 'Promise'?async 函数的返回值必须套一层 Promise<...>:「一个将来会兑现成 User 的承诺」31。
const getUser = async (id: string): Promise<User> => {
const user = await db.users.get(id);
return user;
};练习里那道 fetch 题把前面几节串成了一个小综合题,值得收进主线:
fetchData 里 await fetch(...) 后 response.json() 悬停是 Promise<any>,
所以数据是 any、测试失败。解法有三条路:
fetch<number>(...)——不行,fetch 不收类型参数(第 4 节的判定法:悬停没尖括号);await response.json<number>()——也不行,json() 同样不收;const data: number = await response.json()——能过,但这是上一节的「type faith」;- 正解:给函数标返回类型
async function fetchData(): Promise<number>—— 从出口把关,数据在返回处被检查32。
这条「从出口把关」的思路,和第 4 节「在入口祈祷」形成鲜明对照——同一个 any 困境, 一个在边界相信,一个在边界把关。
9. 练习题精要:七道题各自多教一件事
原书本章的练习密度全章最高(4-14 到 4-20 共七道),多数解法正文已覆盖, 这里只捡四道「解法之外还多教一件事」的走查。
4-15:? 和默认值不能同场
给可选参数加默认值,手痒的写法是 last?: string = "Pocock"——
TypeScript 当场拒绝:Parameter cannot have question mark and initializer33。
理由一句话:可选性和默认值说的是同一件事,留一个就行。
有默认值时,参数天然可选(不传就用默认值),? 成了冗余的重复声明——
所以正确写法是把问号去掉:(first: string, last = "Pocock")33。
这个报错也是「同义修饰符冲突」的通用样本:以后见到「cannot have A and B」
一类的报错,先问 A 和 B 是不是重复表达。
4-19:void vs undefined:为什么回调永远该标 void
一个收回调的函数,把回调标成 () => undefined,然后一个返回 string 的函数
传不进去:() => string is not assignable to () => undefined34。
这暴露了 undefined 作为返回类型的严格性:它要求实现真的返回 undefined,
而不是「不返回」。void 才是「我不关心返回什么」的正确表达——
比较时返回值被忽略,string 返回的函数自然过关34。
把这条和第 7 节合起来,规则完整了:给回调定型,永远优先 () => void;
只有当你真的要检查「返回了 undefined」时(罕见),才用 () => undefined。
4-20:fetch 的 any 从哪来,两种合法的堵法
fetchData 的返回类型悬停是 Promise<any>——源头在两处:
fetch 本身不收类型参数(fetch<number>(...) 报错,和 JSON.parse 同病),
response.json() 的返回类型就写死是 Promise<any>35。
堵 any 的两条路,原书给了优劣排序:
// 路一(可行但局部):给 data 标注——把 any 挤进 number 的槽位
const data: number = await response.json(); // any 赋给 number,合法
// 路二(更好):给函数标返回类型——类型从出口把关
async function fetchData(): Promise<number> { /* ... */ }路一的标注只堵住了一个变量;路二把契约写在函数签名上,所有调用点同时受益——
这是「返回值标注」威力的又一次演示36。中间还有个值得记住的报错:
你若是先写成 : number,TypeScript 会提示
「async 函数的返回类型必须是全局 Promise 类型,你是想写 Promise 吗」——
编译器连修法都替你想好了36。
4-14 与 4-16:最小改动的示范
这两道题的解法本身一句话:可选参数加 ?(4-14),rest 参数标 ...strings: string[](4-16)37。
值得带走的是题型:它们的起点都是「调用报错:Expected 2 arguments, but got 1」
和「rest 参数隐式 any[]」——这两个报错就是第 5 节规则的报错原文,
做题的过程就是「认报错 → 回忆规则 → 最小改动」的完整循环,和真实工作同构。
4-17:函数类型标注的三级台阶
modifyUser(users, id, makeChange) 的 makeChange 是裸参数,隐式 any。
这道题妙在解法不是一步到位的,而是走了三级台阶,每一级都踩在一条报错上:
第①级:makeChange: () => any
→ 新报错:Expected 0 arguments, but got 1
→ 教训:函数类型里的参数列表是契约,「不收参数」就真不能传参
第②级:makeChange: (user: User) => any
→ 能传参了,但返回值没人管:name: 123 这种错也放行
第③级:makeChange: (user: User) => User
→ 参数、返回值都有契约;写回调时 User 的属性还能自动补全
图说:三级台阶 = 「能调用 → 参数对 → 返回对」,
函数类型标注的每个部件(参数列表、返回类型)各司其职[^45]。原书还补了最后一步整洁化:把这个函数类型抽成别名
type MakeChangeFunc = (user: User) => User;——
行为完全一样,但函数类型要复用时,别名是正解38。
这一题把第 6 节「函数本身也是一种类型」从陈述变成了手感:
函数类型的每个零件(收什么、返回什么)都是可检查的契约。
10. 这一章在全书链条中的位置
第 04 章小结把整套基础收拢成一句话:注解与推断是地基;参数必须注解、any 是逃生门、 对象/数组/函数是三种复合形状、void 标记无返回、async 归 Promise 管39。 这些零件拼起来,你已经能类型化一个中型模块的绝大部分代码; 下一章(第 06 章)解决的是它们拼不动的问题——「一个值是几种可能之一」时怎么办。
11. 作者的判断与证据(分开标)
书里有据的:
- 数组两种写法等价、报错用方括号形式——语言事实1。
- 「内联数组元素类型不如抽别名」——明确的风格主张(「we prefer extracting」),理由是可复用3。
- 「判定能否传类型参数:悬停看尖括号」——可操作的经验法则,配了两个正反函数例证1516。
- 「type faith vs type safe」——概念区分,配了「标成 number 也不拦」的实证20。
- 「不关心结果的回调标 () => void」——由 void/undefined 对照练习推得的规则2930。
原书没说的(我们补):
- 数组/元组在其他静态语言里的对应物——补充(不在书里,来自通用知识): 元组接近 Python 的 tuple 与 Rust 的定长数组;「元组成员名运行时不存在」这一点与 Python 的 NamedTuple 不同(后者真有运行时对象)。
- 第 4 节提到的运行时校验(schema 校验)——书里点到即止,我们判断块里补的边界处理即由此而来。
12. 边界与局限
unknown与never未展开:本章两次遇到unknown(空 Set、JSON 之前),它的完整含义第 06、13 章才给。- 函数类型的高级形态(泛型函数、重载、断言函数)是第 17 章;本章的函数类型是「死」签名。
- Promise 只到门口:怎么自己设计 Promise 的泛型参数,第 16 章讲泛型时再回头。
- JSON.parse 的正解(类型谓词、schema 校验)超出本书范围;本章只教到「标注 = type faith」为止。
13. 可带走的
- 数组:
string[]与Array<string>等价;报错用方括号形式,跟着它写。 - 装对象的数组,优先抽别名(单一事实源的又一次复用)。
- 元组 = 固定座位:
[string, number];座位可命名(纯文档)、可选(elevation?)。 new Set<string>()/new Map<number, User>():值和类型都能传给函数。- 判定法:悬停函数,签名里有尖括号才能传类型参数——大多数函数不能。
JSON.parse永远返回 any;给它标注是 type faith(类型信仰),不是类型安全。- 可选参数
?和默认值=不能同时写;有默认值就够可选。 - 不关心返回值的回调标
() => void;() => undefined会错拒有返回值的函数。 - async 函数返回类型必须是
Promise<T>;从函数出口把关,比在数据入口祈祷可靠。
14. 原文地图
| 主题 | 原书位置 | 原文位置 |
|---|---|---|
| 数组两种语法 | Arrays | text/15-fm-arrays.txt:3(搜「two different syntaxes」) |
| 报错用方括号形式 | 同上 | text/15-fm-arrays.txt:22(搜「error messages」) |
| push 错类型被抓 | 同上 | text/15-fm-arrays.txt:53(搜「Karma」) |
| 元组与数组的对比 | 同上 | text/15-fm-arrays.txt:60(搜「fixed number of elements」) |
| 命名元组与「名字运行时不存在」 | 同上 | text/15-fm-arrays.txt:94(搜「don’t do anything at runtime」) |
| 可选元组成员 | 同上 | text/15-fm-arrays.txt:304(搜「optional modifier」) |
| 「优先抽成新类型」的偏好 | 同上 | text/15-fm-arrays.txt:231(搜「prefer extracting」) |
| 传类型给另一个类型 | Passing Types to Functions | text/16-fm-passing-types-to-functions.txt:6(搜「as an argument to another type」) |
空 Set 的 Set<unknown> | Passing Types to Set | text/17-fm-passing-types-to-set.txt:6(搜「Set<unknown>」) |
| 「值和类型都能传给函数」 | 同上 | text/17-fm-passing-types-to-set.txt:36(搜「types as well as values」) |
| 大多数函数收不了类型参数 | Not All Functions Can Receive Types | text/18-fm-not-all-functions-can-receive-types.txt:3(搜「Most functions」) |
| 悬停判定法(getElementById vs querySelector) | 同上 | text/18-fm-not-all-functions-can-receive-types.txt:32(搜「check whether it has any angle brackets」) |
| Map 的两个类型参数 | 同上 | text/18-fm-not-all-functions-can-receive-types.txt:72(搜「new Map<number, User>」) |
| JSON.parse 返回 any | 同上 | text/18-fm-not-all-functions-can-receive-types.txt:128(搜「reviver」) |
| type faith 的警告 | 同上 | text/18-fm-not-all-functions-can-receive-types.txt:145(搜「type faith」) |
| 可选参数为 `string | undefined` | Typing Functions |
| 默认值可省标注(推断) | 同上 | text/19-fm-typing-functions.txt:43(搜「infer the type」) |
? 与 = 互斥 | 同上 | text/19-fm-typing-functions.txt:282(搜「question mark and initializer」) |
| rest 参数隐式 any[] | 同上 | text/19-fm-typing-functions.txt:303(搜「implicitly has an 'any[]'」) |
| 返回值标注 | 同上 | text/19-fm-typing-functions.txt:56(搜「closing parenthesis」) |
| 函数类型语法 | 同上 | text/19-fm-typing-functions.txt:118(搜「type Mapper」) |
| void = 有意忽略返回值 | 同上 | text/19-fm-typing-functions.txt:156(搜「deliberately ignored」) |
| void 忽略返回值的比较 | 同上 | text/19-fm-typing-functions.txt:520(搜「ignore the return value」) |
| async 必须返回 Promise | 同上 | text/19-fm-typing-functions.txt:607(搜「must be the global Promise type」) |
| fetchData 正解(出口把关) | 同上 | text/19-fm-typing-functions.txt:610(搜「Promise<number>」) |
| 本章小结(基础收拢) | Summary | text/20-fm-summary.txt:3(搜「foundational concepts」) |
Footnotes
-
出处:「Arrays」第 22 段(
text/15-fm-arrays.txt:22,搜「error messages」)。原文:两种语法等价,方括号更简洁,而且「是 TypeScript 呈现错误消息的方式」。 ↩ ↩2 -
出处:「Arrays」第 53–56 段(
text/15-fm-arrays.txt:53,搜「Karma」)。 ↩ -
出处:「Arrays」第 231 段(
text/15-fm-arrays.txt:231,搜「prefer extracting」)。 ↩ ↩2 -
出处:「Arrays」第 60–70 段(
text/15-fm-arrays.txt:63,搜「Rubber Soul", 1965」)。 ↩ -
出处:「Arrays」第 83 段(
text/15-fm-arrays.txt:83,搜「index 0」)。 ↩ -
出处:「Arrays」第 304–314 段(
text/15-fm-arrays.txt:307,搜「elevation?: number」)。 ↩ -
出处:「Arrays」第 94 段(
text/15-fm-arrays.txt:94,搜「don’t do anything at runtime」)。 ↩ -
出处:「Arrays」第 276 段(
text/15-fm-arrays.txt:276,搜「x: number, y: number」)。 ↩ -
出处:「Passing Types to Functions」第 6 段(
text/16-fm-passing-types-to-functions.txt:6,搜「as an argument to another type」)。 ↩ -
出处:「Passing Types to Set」第 6 段(
text/17-fm-passing-types-to-set.txt:6,搜「Set<unknown>」)。 ↩ -
出处:「Passing Types to Set」第 15–19 段(
text/17-fm-passing-types-to-set.txt:19,搜「Set<string>」)。 ↩ -
出处:「Passing Types to Set」第 25–34 段(
text/17-fm-passing-types-to-set.txt:30,搜「red squiggly line under 8」)。 ↩ -
出处:「Passing Types to Set」第 36 段(
text/17-fm-passing-types-to-set.txt:36,搜「types as well as values」)。 ↩ -
出处:「Not All Functions Can Receive Types」第 52–55 段(
text/18-fm-not-all-functions-can-receive-types.txt:55,搜「Map<any, any>」)。 ↩ -
出处:「Not All Functions Can Receive Types」第 16 段(
text/18-fm-not-all-functions-can-receive-types.txt:16,搜「getElementById」)与第 25 段(搜「querySelector」)、第 32 段(搜「angle brackets」)。 ↩ ↩2 -
出处:「Not All Functions Can Receive Types」第 3 段(
text/18-fm-not-all-functions-can-receive-types.txt:3,搜「Most functions」)。 ↩ ↩2 -
出处:「Not All Functions Can Receive Types」第 91 段(
text/18-fm-not-all-functions-can-receive-types.txt:91,搜「Expected 0 type arguments」)。 ↩ -
出处:「Not All Functions Can Receive Types」第 128–131 段(
text/18-fm-not-all-functions-can-receive-types.txt:131,搜「always returns any」)。 ↩ -
出处:「Not All Functions Can Receive Types」第 142 段(
text/18-fm-not-all-functions-can-receive-types.txt:142,搜「disables type checking」)。 ↩ -
出处:「Not All Functions Can Receive Types」第 145 段(
text/18-fm-not-all-functions-can-receive-types.txt:145,搜「type faith」)。 ↩ ↩2 -
出处:「Typing Functions」第 24 段(
text/19-fm-typing-functions.txt:24,搜「string | undefined」)。 ↩ -
出处:「Typing Functions」第 43 段(
text/19-fm-typing-functions.txt:43,搜「infer the type」)。 ↩ -
出处:「Typing Functions」第 282–283 段(
text/19-fm-typing-functions.txt:282,搜「question mark and initializer」)。 ↩ -
出处:「Typing Functions」第 303 段(
text/19-fm-typing-functions.txt:303,搜「implicitly has an 'any[]'」)。 ↩ -
出处:「Typing Functions」第 76 段(
text/19-fm-typing-functions.txt:76,搜「ensure that a function returns」)。 ↩ -
出处:「Typing Functions」第 380–422 段(
text/19-fm-typing-functions.txt:398,搜「Expected 0 arguments」)、第 417 段(搜「(user: User) => User」)、第 422 段(搜「autocompletion」)。 ↩ -
出处:「Typing Functions」第 139–149 段(
text/19-fm-typing-functions.txt:142,搜「WithOptional」)。 ↩ -
出处:「Typing Functions」第 156–159 段(
text/19-fm-typing-functions.txt:158,搜「void」)。 ↩ -
出处:「Typing Functions」第 504–506 段(
text/19-fm-typing-functions.txt:505,搜「parameter of type '() => undefined'」)。 ↩ ↩2 -
出处:「Typing Functions」第 520 段(
text/19-fm-typing-functions.txt:520,搜「ignore the return value」)。 ↩ ↩2 -
出处:「Typing Functions」第 175–186 段(
text/19-fm-typing-functions.txt:607,搜「must be the global Promise type」)。 ↩ -
出处:「Typing Functions」第 568–618 段(
text/19-fm-typing-functions.txt:610,搜「Promise<number>」)。 ↩ -
出处:「Typing Functions」练习 4-15 解答(
text/19-fm-typing-functions.txt:282,搜「question mark and initializer」)。「The optionality is already implied by the default value」见第 283 段。 ↩ ↩2 -
出处:「Typing Functions」练习 4-19 与解答(
text/19-fm-typing-functions.txt:505,搜「assignable to parameter of type '() => undefined'」);解法与「void tells TypeScript to ignore the return value」见第 514–520 段。 ↩ ↩2 -
出处:「Typing Functions」练习 4-20 的排查(
text/19-fm-typing-functions.txt:568,搜「doesn’t accept type arguments」)。response.json(): Promise<any>的悬停见第 542 段。 ↩ -
出处:「Typing Functions」练习 4-20 的两条解法(
text/19-fm-typing-functions.txt:598,搜「best way to solve this problem」)。async 返回类型报错文本见第 607 段(搜「must be the global Promise type」)。 ↩ ↩2 -
出处:「Typing Functions」练习 4-14 解答(
text/19-fm-typing-functions.txt:219,搜「last?: string」)与练习 4-16 解答(text/19-fm-typing-functions.txt:313,搜「strings: string[]」)。 ↩ -
出处:「Typing Functions」练习 4-17 解答(
text/19-fm-typing-functions.txt:398,搜「Expected 0 arguments, but got 1」);第③级(user: User) => User见第 417 段;别名整理见第 426 段(搜「MakeChangeFunc」)。 ↩ -
出处:「Summary」第 3–21 段(
text/20-fm-summary.txt:3,搜「foundational concepts」);any 的定性见第 9 段(搜「disables TypeScript’s type checking entirely」)。 ↩