编程语言研究书库

数组、元组与函数类型 — 第一批复合类型

数组、元组与函数类型 — 第一批复合类型

这一章讲三件事: 「一篮子同类型的东西」怎么描述(数组、元组); 「给函数传一个类型当参数」是怎么回事(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。 三种解法:

  1. 创建时就放值:new Set(["CD", "DVD"]) → 推断出 Set<string>11;
  2. 创建后传类型:new Set<string>() → 空集合,但声明只装字符串;此后 formats.add(8) 当场红线12;
  3. 想要别的元素类型就换别的参数。

原书对这一步的定性是:「你可以给函数传值,也可以给函数传类型」——这是 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")  ✅

15

「大多数函数收不了类型参数」——这句话原书是当标题写的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[]): void

void 是 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、测试失败。解法有三条路:

  1. fetch<number>(...)——不行,fetch 不收类型参数(第 4 节的判定法:悬停没尖括号);
  2. await response.json<number>()——也不行,json() 同样不收;
  3. const data: number = await response.json()——能过,但这是上一节的「type faith」;
  4. 正解:给函数标返回类型 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. 可带走的

  1. 数组:string[] 与 Array<string> 等价;报错用方括号形式,跟着它写。
  2. 装对象的数组,优先抽别名(单一事实源的又一次复用)。
  3. 元组 = 固定座位:[string, number];座位可命名(纯文档)、可选(elevation?)。
  4. new Set<string>() / new Map<number, User>():值和类型都能传给函数。
  5. 判定法:悬停函数,签名里有尖括号才能传类型参数——大多数函数不能。
  6. JSON.parse 永远返回 any;给它标注是 type faith(类型信仰),不是类型安全。
  7. 可选参数 ? 和默认值 = 不能同时写;有默认值就够可选。
  8. 不关心返回值的回调标 () => void;() => undefined 会错拒有返回值的函数。
  9. async 函数返回类型必须是 Promise<T>;从函数出口把关,比在数据入口祈祷可靠。

14. 原文地图

主题原书位置原文位置
数组两种语法Arraystext/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 Functionstext/16-fm-passing-types-to-functions.txt:6(搜「as an argument to another type」)
空 Set 的 Set<unknown>Passing Types to Settext/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 Typestext/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」)
可选参数为 `stringundefined`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>」)
本章小结(基础收拢)Summarytext/20-fm-summary.txt:3(搜「foundational concepts」)

Footnotes

  1. 出处:「Arrays」第 22 段(text/15-fm-arrays.txt:22,搜「error messages」)。原文:两种语法等价,方括号更简洁,而且「是 TypeScript 呈现错误消息的方式」。 ↩ ↩2

  2. 出处:「Arrays」第 53–56 段(text/15-fm-arrays.txt:53,搜「Karma」)。 ↩

  3. 出处:「Arrays」第 231 段(text/15-fm-arrays.txt:231,搜「prefer extracting」)。 ↩ ↩2

  4. 出处:「Arrays」第 60–70 段(text/15-fm-arrays.txt:63,搜「Rubber Soul", 1965」)。 ↩

  5. 出处:「Arrays」第 83 段(text/15-fm-arrays.txt:83,搜「index 0」)。 ↩

  6. 出处:「Arrays」第 304–314 段(text/15-fm-arrays.txt:307,搜「elevation?: number」)。 ↩

  7. 出处:「Arrays」第 94 段(text/15-fm-arrays.txt:94,搜「don’t do anything at runtime」)。 ↩

  8. 出处:「Arrays」第 276 段(text/15-fm-arrays.txt:276,搜「x: number, y: number」)。 ↩

  9. 出处:「Passing Types to Functions」第 6 段(text/16-fm-passing-types-to-functions.txt:6,搜「as an argument to another type」)。 ↩

  10. 出处:「Passing Types to Set」第 6 段(text/17-fm-passing-types-to-set.txt:6,搜「Set<unknown>」)。 ↩

  11. 出处:「Passing Types to Set」第 15–19 段(text/17-fm-passing-types-to-set.txt:19,搜「Set<string>」)。 ↩

  12. 出处:「Passing Types to Set」第 25–34 段(text/17-fm-passing-types-to-set.txt:30,搜「red squiggly line under 8」)。 ↩

  13. 出处:「Passing Types to Set」第 36 段(text/17-fm-passing-types-to-set.txt:36,搜「types as well as values」)。 ↩

  14. 出处:「Not All Functions Can Receive Types」第 52–55 段(text/18-fm-not-all-functions-can-receive-types.txt:55,搜「Map<any, any>」)。 ↩

  15. 出处:「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

  16. 出处:「Not All Functions Can Receive Types」第 3 段(text/18-fm-not-all-functions-can-receive-types.txt:3,搜「Most functions」)。 ↩ ↩2

  17. 出处:「Not All Functions Can Receive Types」第 91 段(text/18-fm-not-all-functions-can-receive-types.txt:91,搜「Expected 0 type arguments」)。 ↩

  18. 出处:「Not All Functions Can Receive Types」第 128–131 段(text/18-fm-not-all-functions-can-receive-types.txt:131,搜「always returns any」)。 ↩

  19. 出处:「Not All Functions Can Receive Types」第 142 段(text/18-fm-not-all-functions-can-receive-types.txt:142,搜「disables type checking」)。 ↩

  20. 出处:「Not All Functions Can Receive Types」第 145 段(text/18-fm-not-all-functions-can-receive-types.txt:145,搜「type faith」)。 ↩ ↩2

  21. 出处:「Typing Functions」第 24 段(text/19-fm-typing-functions.txt:24,搜「string | undefined」)。 ↩

  22. 出处:「Typing Functions」第 43 段(text/19-fm-typing-functions.txt:43,搜「infer the type」)。 ↩

  23. 出处:「Typing Functions」第 282–283 段(text/19-fm-typing-functions.txt:282,搜「question mark and initializer」)。 ↩

  24. 出处:「Typing Functions」第 303 段(text/19-fm-typing-functions.txt:303,搜「implicitly has an 'any[]'」)。 ↩

  25. 出处:「Typing Functions」第 76 段(text/19-fm-typing-functions.txt:76,搜「ensure that a function returns」)。 ↩

  26. 出处:「Typing Functions」第 380–422 段(text/19-fm-typing-functions.txt:398,搜「Expected 0 arguments」)、第 417 段(搜「(user: User) => User」)、第 422 段(搜「autocompletion」)。 ↩

  27. 出处:「Typing Functions」第 139–149 段(text/19-fm-typing-functions.txt:142,搜「WithOptional」)。 ↩

  28. 出处:「Typing Functions」第 156–159 段(text/19-fm-typing-functions.txt:158,搜「void」)。 ↩

  29. 出处:「Typing Functions」第 504–506 段(text/19-fm-typing-functions.txt:505,搜「parameter of type '() => undefined'」)。 ↩ ↩2

  30. 出处:「Typing Functions」第 520 段(text/19-fm-typing-functions.txt:520,搜「ignore the return value」)。 ↩ ↩2

  31. 出处:「Typing Functions」第 175–186 段(text/19-fm-typing-functions.txt:607,搜「must be the global Promise type」)。 ↩

  32. 出处:「Typing Functions」第 568–618 段(text/19-fm-typing-functions.txt:610,搜「Promise<number>」)。 ↩

  33. 出处:「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

  34. 出处:「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

  35. 出处:「Typing Functions」练习 4-20 的排查(text/19-fm-typing-functions.txt:568,搜「doesn’t accept type arguments」)。response.json(): Promise<any> 的悬停见第 542 段。 ↩

  36. 出处:「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

  37. 出处:「Typing Functions」练习 4-14 解答(text/19-fm-typing-functions.txt:219,搜「last?: string」)与练习 4-16 解答(text/19-fm-typing-functions.txt:313,搜「strings: string[]」)。 ↩

  38. 出处:「Typing Functions」练习 4-17 解答(text/19-fm-typing-functions.txt:398,搜「Expected 0 arguments, but got 1」);第③级 (user: User) => User 见第 417 段;别名整理见第 426 段(搜「MakeChangeFunc」)。 ↩

  39. 出处:「Summary」第 3–21 段(text/20-fm-summary.txt:3,搜「foundational concepts」);any 的定性见第 9 段(搜「disables TypeScript’s type checking entirely」)。 ↩

On this page