Skip to content

TypeScript 核心(二) ​

本页对应 TypeScript 核心,共 6 段视频,约 1 小时 4 分。

学习目标 ​

  • 能编写带可选参数和无返回值(void)的函数,并说明可选参数必须位于参数列表末尾、void 与 undefined 的区别。
  • 能使用 interface 定义对象类型,并通过问号设置可选属性、通过 extends 实现接口继承。
  • 能使用 type 定义对象类型,并用交叉类型(&)模拟继承,能对比 interface 与 type 的异同并做出选择。
  • 能使用字面量类型配合联合类型限定变量的可选范围,并解释 const 与 let 声明字面量时的类型推断差异。
  • 能说明 TypeScript 类型推论机制,在变量声明和函数返回值场景中判断推断结果,并解释 any 的风险及避免使用的原因。
  • 能根据给定的嵌套响应对象或表单数据,选择 interface 或 type 完成类型定义并通过类型校验。

知识点 ​

函数类型:可选参数与无返回值 ​

为什么需要:函数参数一旦注解类型,默认就是必填项;但业务里常有“可传可不传”的参数。函数也可能只做打印、遍历等动作,没有返回值,需要明确标注。

怎么想:可选参数表示“可传可不传;一旦传了,类型必须正确”。写法是在参数名后、冒号前加 ?。无返回值函数用 void 标注,表示该函数不返回结果。

怎么做:

ts
function buildName(firstName: string, lastName?: string): string {
  if (lastName) {
    return `${firstName}${lastName}`;
  }
  return firstName;
}

buildName("A");       // 合法
buildName("A", "B");  // 合法
// buildName("A", 123); // 报错:number 不能赋给 string

function printArr(arr: number[]): void {
  arr.forEach(item => console.log(item));
}

调试时可以看到:只传 "A" 输出 A;传 "A","B" 输出 AB;第二个参数传数字会报类型错误。void 函数若用变量接收,得到的是 void 类型。

易错点:可选参数必须放在所有必选参数末尾;把可选参数提前会报“必选参数不能位于可选参数之后”。另外,void 与 undefined 不是一回事:void 表示没有返回值;若函数返回值标为 undefined,则必须 return undefined。

interface:描述对象形状与业务场景 ​

为什么需要:对象数据需要约束属性名、属性数量和属性类型。前后端通信时,表单提交、列表渲染都依赖稳定的数据结构。

怎么想:把 interface 理解为“对象形状说明书”:属性不能多、不能少,类型要匹配。典型场景有两个:前端向后端提交表单时按接口文档定义字段;前端渲染后端列表时获得智能提示。

怎么做:

ts
interface Person {
  name: string;
  age: number;
}

const p: Person = { name: "Jack", age: 18 };

interface Form {
  username: string;
  password: string;
}

const form: Form = { username: "jack", password: "123456" };

调试时,少写 name、多写 hobby、把 age 写成字符串都会报错。渲染列表时,输入 item. 能自动提示属性,减少查文档和拼写错误。

易错点:interface 约束的是对象结构,不是随便一个值;属性多一个少一个都不行,类型也必须一致。

interface 的可选属性与继承 ​

为什么需要:对象里有些属性可传可不传,例如按钮的 size;多个接口有重复字段时,需要复用类型。

怎么想:可选属性在属性名后加 ?;继承用 extends,子接口拥有父接口属性,并可追加自己的属性。

怎么做:

ts
interface Props {
  type: string;
  size?: string;
}

const props1: Props = { type: "success" };
const props2: Props = { type: "success", size: "large" };

interface GoodsType {
  id: string;
  price: number;
}

interface DiscountGoodsType extends GoodsType {
  discountPrice: number;
}

调试时,size 不传合法,传了但写成数字会报错;继承后的对象缺少 id 或 discountPrice 都会报错。

易错点:可选属性不是“随便类型”,传了仍要满足类型;继承来的属性和自身属性都不能缺失。

type:对象类型、交叉类型与选择 ​

为什么需要:对象类型除了 interface,还可以用类型别名 type 描述;type 还能配合交叉类型模拟继承。

怎么想:type 后跟名称和等号,再写对象结构;继承模拟用 & 连接父类型和新增结构。同名 interface 会合并,同名 type 会报错;讲师建议对象注解优先用 type,因为它更灵活。

怎么做:

ts
type Person = { name: string; age: number };
const p2: Person = { name: "Jack", age: 18 };

type GoodsType = { id: string; price: number };
type DiscountGoodsType = GoodsType & { discountPrice: number };

调试时,type 定义的对象同样不能多属性、少属性或类型不符;交叉类型后的对象必须同时具备 id、price、discountPrice。

易错点:type 同名会直接报错;交叉类型不是“或”,而是“同时满足”。

字面量类型与联合类型 ​

为什么需要:普通 string、number 太宽泛。性别只有“男/女”,状态码只有几个值,需要精确可选范围。

怎么想:字面量类型用具体值作类型,通常和联合类型配合,限定只能取某几个值。

怎么做:

ts
type Gender = "男" | "女";
let gender: Gender = "男";
// gender = "哈哈"; // 报错

type Code = 1001 | 1002 | 1003;
let code: Code = 1001;
// code = 1004; // 报错

调试时,输入变量会有“男/女”提示;写其他字符串或数字会报错。let str = "123" 推断为 string,const str = "456" 推断为字面量 "456"。

易错点:字面量类型不单独乱用,通常配联合类型;const 与 let 的推断结果不同。

类型推论与 any ​

为什么需要:每次手写类型注解很繁琐;TS 会根据赋值和返回值自动推断类型,减少代码量。any 则用于彻底关闭类型检查,但会失去类型提示。

怎么想:声明变量并赋值、函数返回值都可被推断。初学建议先写类型,熟练后能省略再省略;不确定变量类型时,把鼠标移上去看提示。any 尽量不用。

怎么做:

ts
let count = 100;       // 推断为 number
// count = false;      // 报错

function add(a: number, b: number) {
  return a + b;        // 返回值推断为 number
}

let value: any = 100;
value = "x";
value = false;

调试时,count 再赋布尔值会报错;add 的返回值被推断为 number。any 变量随便赋值、随便赋给别人都不报错,但输入 value. 也没有可靠提示。

易错点:any 不是“万能好类型”,它让 TS 退回到类似 JS 的无类型检查状态,漏洞风险更高,应尽量避免。

先抓住定义:TS 是“具有类型语法的 JavaScript” ​

为什么需要: JavaScript 写起来灵活,但变量、函数参数到底该传什么,往往要运行起来才发现问题。TypeScript 在 JavaScript 语法上增加类型语法,让我们在开发阶段就能表达“这里应该是什么类型”,并借助类型检查提前发现不一致。

怎么想: 先把 TS 理解成“JavaScript + 类型语法”,不要一上来把它当成完全陌生的语言。笔记里的原话是:“TypeScript 是具有类型语法的 JavaScript,是一门强类型的编程语言。”这句话有两个重点:一是仍然写 JavaScript 风格的代码;二是类型会成为约束。

TypeScript 类型语法示意图

怎么做: 从最简单的变量注解开始。转写稿中的 count 例子可以还原为:

ts
let count: number = 100;

count = 200; // 可以
// count = false; // 报错:不能将布尔类型分配给 number

这里 : number 就是类型注解。它表达的不是“运行时把 count 变成 number”,而是开发时告诉 TS:这个变量只能接收 number 类型的数据。

易错点: 不要把类型注解当成运行时逻辑。类型写错时,编辑器会出现红色波浪线,鼠标移上去能看到“不能将某某类型分配给某某类型”的提示;这不是等到页面运行才暴露的问题。

强类型体现在哪里:参数、返回值和调用检查 ​

为什么需要: 函数是业务代码里最常复用的单位。参数类型不明确时,调用方可能传错;返回值不明确时,接收方也可能用错。转写稿里讲函数类型时反复强调:参数一旦注解类型,就既要满足类型要求,也默认是必填项。

怎么想: 先确定函数的“输入”和“输出”。参数是输入,返回值是输出。输入输出确定后,函数体内部和外部调用都有了约束。

怎么做: 用转写稿里的求和函数说明:

ts
function add(a: number, b: number) {
  return a + b;
}

const result = add(1, 2); // result 被推断为 number

参数 a、b 都注解为 number,所以调用时传数字才符合要求。转写稿还提到可选参数:如果某个参数可传可不传,可在冒号前加问号,例如 lastName?: string;一旦传了,就必须满足 string 类型。

易错点: 可选参数不是随便放。转写稿中特意演示了把可选参数提到前面会报错,提示“必选参数不能位于可选参数之后”。所以可选参数要放在所有参数的末尾。另一个易错点是:可选参数“可不传”,但传了就不能传错类型。

类型推断:不是每处都要手写类型 ​

为什么需要: 如果每个变量、每个返回值都手写类型,代码会很啰嗦。TS 提供了类型推断机制:在没有显式写类型注解时,它也会根据初始值或上下文给出类型。

怎么想: 有初始值时,先让 TS 自己推断;推断结果不清楚,或者团队规范要求显式表达时,再补注解。转写稿里说得很直白:类型推断体现了“不用手写,但也会自动添加类型”的机制,目的是让开发者少写代码。

怎么做: 变量赋值场景:

ts
let count = 100; // 推断为 number
count = 200;     // 可以
// count = false; // 报错

函数返回值场景:

ts
function add(a: number, b: number) {
  return a + b;
}

因为 a、b 都是 number,a + b 也是 number,所以返回值不用再手写,TS 会推断为 number。

易错点: 初学阶段建议先多写类型注解,熟悉后再省略“能省略的地方”。转写稿还给了一个实用调试技巧:把鼠标移到变量上,看它当前被推断成什么类型;不知道类型时,这个办法很快。

any:看似省事,实际会失去类型检查 ​

为什么需要: 转写稿提到,有些开发者为了省事会用 any。它可以让变量跳过类型检查,赋值、访问属性、调用函数都不容易报类型错误,因此常被拿来应付临时场景。

怎么想: any 的本质是“放弃类型约束”。TS 最核心的价值是类型检查与类型提示;一旦大量使用 any,就接近回到普通 JavaScript 的体验,程序里潜在的问题也更难提前发现。

怎么做: 转写稿的演示可以概括为:

ts
let obj: any = 100;
obj = "字符串"; // 可以
obj = false;    // 可以

let num: number = 100;
num = obj;      // 可以,因为 obj 是 any

易错点: any 不是“万能安全类型”,而是关闭检查。转写稿明确建议实际开发中尽量避免使用它。另一个易错点是:用了 any 后,点语法提示也会变弱,享受不到 TS 的类型提示。

本节调试方法:用报错和悬停验证理解 ​

为什么需要: 只看定义容易停留在概念上。转写稿里多次通过“故意写错—看红色波浪线—读提示”的方式验证类型规则,这比死记结论更可靠。

怎么想: 先写一个符合类型的值,再写一个不符合类型的值,观察 TS 在哪里报错、报错信息说“不能将什么分配给什么”。同时把鼠标移到变量或函数返回值上,看推断结果。

怎么做: 例如先写 let count: number = 100,再把 count 赋成 false,看编辑器提示;再写 function add(a: number, b: number) { return a + b },把鼠标移到调用结果上,确认它是 number。

易错点: 读报错时要抓住“类型不匹配”这个核心,不要只看到红色波浪线就慌。转写稿里的调试过程也说明:TS 的报错是在帮我们定位类型问题,而不是代码一定完全不能运行。

先看本节要解决的问题 ​

这一节笔记只有两个要点:静态类型检查能提前发现代码错误;良好的代码提示能提升开发效率。它们看起来像“体验优化”,其实是 TypeScript 最直接的价值:把很多原本要等运行时才暴露的问题,提前到写代码和保存文件时暴露;把原本要翻接口文档、靠记忆拼字段的工作,变成编辑器里的自动联想。

为什么需要静态类型检查 ​

JavaScript 里,参数传错、对象字段拼错、类型不一致,往往要等函数执行到那一行才报错。TypeScript 的思路是:只要你能把“这里应该是什么类型”写清楚,编辑器就能在保存时先替你检查一遍。

转写稿里有一个很典型的调试过程:build 函数负责合并两个名字,第二个参数 lastName 写成可选参数后,不传可以;传一个字符串 B 也可以;但如果传数字,编辑器马上提示“number 不能赋值给 string 类型的参数”。这就是“要么别传,传了就必须类型正确”。

静态类型检查提前发现参数类型错误

对象场景更明显。用 interface 约束一个对象后,少一个 name 属性会报“缺少属性”;多一个 hat 属性也会报错;age 本来要求 number,写成带引号的字符串也会报错。也就是说,属性的数量、名称和类型都被提前约定了。

静态类型检查提前发现对象属性错误

怎么想:把“约定”提前写成类型 ​

不要等到运行失败才想“这里应该传什么”。写函数时先想参数和返回值;写表单时先想后端接口要什么字段;写列表时先想每一项对象长什么样。类型不是装饰,而是把口头约定变成可检查的规则。

比如字面量联合类型可以限制取值范围:性别只能是“男”或“女”,传“哈哈哈”就会报错;接口返回的 code 只允许 1001、1002、1003 时,传 1004 也会被拦住。这样错误在开发阶段就暴露,而不是等用户点到某个页面才发现。

怎么做:让报错在保存时就出现 ​

第一,给关键参数、返回值、对象结构加注解;第二,保存后看编辑器里的红色波浪线;第三,把鼠标移到报错处看具体原因;第四,修正调用处或类型定义。转写稿里的操作就是“改代码—保存—看右侧结果/看波浪线—悬停读错误—再修正”。

易错点:别把类型检查关掉 ​

最常见的逃避方式是随手写 any。转写稿明确演示了:变量一旦是 any,可以随便赋值,也可以赋给其他类型,但同时也享受不到类型提示,相当于又回到了没有类型检查的状态。另一个易错点是可选参数:不传可以,但一旦传了,类型仍必须正确;可选参数还应放在参数末尾。

为什么需要良好的代码提示 ​

代码提示的价值在“少查、少记、少拼错”。转写稿里模拟商品列表时,给列表项加上类型后,输入 item. 会自动提示 id、price;渲染后端返回的嵌套对象时,先点外层属性,再点内层对象,title、content 也能被提示出来。以前可能要截图接口文档、对照着写,现在编辑器直接告诉你有哪些字段。

类型提示提升开发效率

怎么想:类型是提示的来源 ​

提示不是凭空来的。你先用 interface 或 type 描述对象结构,编辑器才知道这个对象身上有哪些属性;你给数组加上元素类型,遍历时才知道 item 是什么。类型定义越贴近后端接口,提示就越准。

怎么做:先注解,再使用点语法 ​

先定义表单、列表项、接口返回值的类型,再把它注解到变量、数组或函数返回值上。之后在遍历、渲染、取值时输入点语法,观察自动联想;选中需要的字段,减少手写拼错。转写稿中 forEach 遍历时输入 item. 能提示 id 和 price,就是这一过程。

易错点:提示不能代替运行时校验 ​

提示只能说明“类型上可能有这个字段”,不能保证后端一定返回。可选属性在提示里可能出现,但使用时仍要判断是否存在。若类型定义写错,提示也会跟着错;若用了 any,提示会消失。因此类型定义要跟接口文档保持一致,关键数据仍要做运行时处理。

把两个好处合起来看 ​

静态类型检查负责“提前拦住明显错误”,代码提示负责“让正确的写法更快出现”。前者提升代码质量,后者提升开发效率。转写稿里的参数报错、对象属性报错、字面量范围限制,以及商品列表和嵌套对象的自动提示,都是这两个好处的具体表现。学习这一节,不是背概念,而是养成一个习惯:先把类型约定写下来,再让编辑器帮你检查和提示。

课件图示 ​

课件第42页:type注解对象 概念:在TS中对于对象数据的类型注解,除了使用interfac

课件第59页:概念:泛型(Generics)是指在定义接口、函数等类型的时候,不预先指定具体的

课件第35页:interface接口类型的作用 作用: 在TS中使用interface接口来描

课件第48页:字面量类型的实际应用 字面量类型在实际应用中通常和联合类型结合起来使用,提供一个

课件第32页:总结 总结 1. 函数类型实际上是给谁标注类型? 参数和返回值 2. 可选参数可

课件第36页:interface的典型场景 场景:在常规业务开发中比较典型的就是前后端数据通信

课件第39页:总结 总结 1. interface接口类型实际限制的是什么? 对象的属性(方法

课件第40页:思考 通常我们的后端接口返回的数据格式具有一定的规范,比如经常见到 的respo

代码示例 ​

示例一:函数类型——可选参数与无返回值(void) ​

ts
// 可选参数:参数名后加 ?,表示可传可不传;传了必须类型正确
function build(firstName: string, lastName?: string): string {
  if (lastName) {
    return `${firstName} ${lastName}`
  }
  return firstName
}

console.log(build('A'))          // A
console.log(build('A', 'B'))     // A B
// console.log(build('A', 123))  // 报错:number 不能赋值给 string

// 无返回值:用 void 注解
function h(arr: number[]): void {
  arr.forEach(item => console.log(item))
}
h([1, 2, 3])   // 依次打印 1 2 3

// 调用后无法用变量接收有意义的返回值
const r = h([1])
console.log(r) // undefined(但 r 的类型是 void,不是 undefined 类型)

要点与易错点

  • lastName?: string 中问号必须写在冒号前面,写成 lastName: ?string 是错的。
  • 可选参数必须放在所有必选参数的末尾,否则报错“必选参数不能位于可选参数之后”。
  • void 与 undefined 不是一回事:void 表示函数无返回值;如果把返回值标注成 undefined,则函数内部必须 return undefined。
  • void 函数不要尝试用变量去接收并参与运算,类型上拿不到有效值。

示例二:interface——可选属性与接口继承 ​

ts
// 可选设置:size 加问号后,赋值时可省略
interface Props {
  type: string
  size?: string
}

const p1: Props = { type: 'success' }              // 不传 size,合法
const p2: Props = { type: 'success', size: 'large' } // 传了,必须是 string
// const p3: Props = { type: 'success', size: 123 }  // 报错

// 接口继承:子接口复用父接口属性
interface GoodsType {
  id: string
  price: number
}

interface DisGoodsType extends GoodsType {
  disPrice: number
}

const goods: DisGoodsType = {
  id: '1001',
  price: 200,
  disPrice: 180
}
// 少 id 报错:缺少属性 id
// 少 disPrice 报错:缺少属性 disPrice
// 多写一个属性同样报错:对象字面量只能指定已知属性

要点与易错点

  • 可选属性传值时,值的类型仍要匹配,size?: string 传 123 会报错。
  • extends 后写的是父接口名,子接口里只写自己新增的属性,不要重复父接口已有的 id、price。
  • 给对象字面量赋值时,属性不能多也不能少,这是 interface 校验最容易被忽略的一点。

示例三:type——交叉类型模拟继承、嵌套对象与字面量联合类型 ​

ts
// type 配合交叉类型(&)模拟继承
type GoodsType = {
  id: string
  price: number
}

type DisGoodsType = GoodsType & {
  disPrice: number
}

const goods: DisGoodsType = {
  id: '1001',
  price: 200,
  disPrice: 180
}

// 嵌套对象:先定义内层,再定义外层
type Data = {
  title: string
  content: string
}

type Res = {
  code: number
  message: string
  data: Data
}

const res: Res = {
  code: 200,
  message: 'success',
  data: { title: '标题', content: '内容' }
}

// 字面量 + 联合类型:精确的可选范围
type Gender = '男' | '女'
let g: Gender = '男'
// g = '哈哈'   // 报错:不能将 "哈哈" 分配给 Gender

type Code = 1001 | 1002 | 1003
type Res2 = {
  code: Code
  message: string
}

const r2: Res2 = { code: 1001, message: 'ok' }
// const r3: Res2 = { code: 1004, message: 'ok' }  // 报错:1004 不在可选范围内

要点与易错点

  • type 定义对象类型时必须写等号:type X = { ... },不要写成 type X { ... }。
  • 交叉类型用 & 连接,顺序不影响结果;GoodsType & { disPrice: number } 等价于继承后再扩展。
  • 嵌套对象建议先里后外定义,外层直接引用内层类型名,不要在一个大括号里硬嵌套。
  • 字面量类型通常不单独使用,要和联合类型 | 配合,才能既精确又实用。
  • type 同名会直接报错;interface 同名会合并(属性取并集,类型冲突才报错),这是二者最明显的差异之一。

常见错误 ​

1. 可选参数写在必选参数前面

  • 现象:function f(a?: string, b: string) 直接标红,提示"必选参数不能位于可选参数之后"。
  • 原因:TS 按位置匹配实参,可选参在前会导致后面的必选参无法确定是否被传值。
  • 修法:把带 ? 的参数全部挪到参数列表末尾;实在需要"中间可省略",改成传对象配置或显式传 undefined。

2. 把 void 和 undefined 当成一回事

  • 现象:给无返回值的函数标 : undefined,或写 return undefined 后仍报类型不符;反过来把返回 undefined 的函数标成 : void 又想去取返回值。
  • 原因:void 表示"不关心返回值",undefined 是一个具体类型,函数标 : undefined 时必须 return undefined。
  • 修法:纯执行副作用的函数用 : void;确实要返回 undefined 才用 : undefined。并且不要用变量去接收 void 函数的返回值。

3. 用 interface 描述的对象赋值时"多一个/少一个属性"就报错

  • 现象:接口定义了 name、age,赋值时多写一个 hobby 或漏写 age,都标红。
  • 原因:interface 约束的是对象"形状",属性名、数量、类型三者都要精确匹配,不是"包含即可"。
  • 修法:确实可传可不传的字段加 ?;需要扩展字段用 extends 或 & 派生新类型,而不是硬塞进原接口。

4. 同名 interface 声明合并引发意外属性冲突

  • 现象:两个文件里都写了 interface Item,合并后多出字段;若两处同名属性类型不同,直接报"类型必须为 xxx"。
  • 原因:同名 interface 会自动声明合并(属性并集),而同名 type 会直接报重复定义。
  • 修法:全局接口注意命名唯一;不希望被合并时统一改用 type。

5. 用 type 模拟继承时漏写交叉连接符

  • 现象:type Sub = Base { extra: number } 报语法错误,或只写了 { extra: number } 导致父类型字段全部丢失。
  • 原因:type 没有 extends,复用必须靠交叉类型 & 组合。
  • 修法:写成 type Sub = Base & { extra: number };注意 & 是"且",不是"或"。

6. 该用字面量联合的地方写成了宽泛基础类型

  • 现象:code: number 或 gender: string 时,传 1004、"哈哈哈"都能通过校验,运行时后端报错。
  • 原因:number / string 只约束大类,不约束取值范围;精确范围要靠字面量类型 + 联合类型。
  • 修法:type Code = 1001 | 1002 | 1003,type Gender = '男' | '女',再注解到字段/参数上。

7. 依赖类型推论时用了空初始值

  • 现象:let list = [] 之后 list.push(1) 报错(推断成 never[]),或 let obj = {} 后加点赋值报错。
  • 原因:推论只看初始值,空值推不出元素/属性类型。
  • 修法:给变量显式注解 let list: number[] = []、let obj: Goods = {} as Goods(或先给完整初始值)。

8. 图省事到处写 any

  • 现象:注解 any 后属性名拼错、调用不存在的方法、把 any 赋值给 number 全都不报错,问题被推迟到运行时报错。
  • 原因:any 会关闭该值的全部类型检查并向下传染,也丢失代码提示。
  • 修法:先试着写具体类型或 unknown(unknown 使用前必须收窄);第三方库缺类型时优先找 @types/* 或 declare 补声明。

练习 ​

练习 1(找错) 下面代码有两处类型问题,指出并改正:

ts
function buildName(lastName?: string, firstName: string): void {
  return firstName + lastName
}

提示:看参数顺序和返回值注解是否与函数体一致。

练习 2(interface 建模) 定义一个 Goods 接口(id: string、price: number),再定义 DiscountGoods 继承它并新增 discountPrice: number;最后声明一个 DiscountGoods 类型变量并正确赋值。要求:id 改成可选属性后再验证一次赋值是否仍合法。

练习 3(type 等价改写) 把练习 2 用 type + 交叉类型重写一遍,并说明在"对象类型注解"场景下你团队应统一用哪种写法、理由是什么。

练习 4(字面量联合) 后端返回体形如 { code: 1001 | 1002 | 1003, message: string, data: { title: string; content: string } }。请先定义内层 data 类型,再定义外层类型(分别用 type 实现),并说明如果 code 写成 number 会有什么后果。

练习 5(推论与 any) 说明下列代码为何报错,并给出两种修复方式:

ts
let ids = []
ids.push(1001)

再补一句:如果把 ids 注解成 any[],这段代码会怎样?代价是什么?

原视频对照 ​

#视频时长
1TS核心-函数类型-可选参和无返回值12:26
2TS核心-interface-概念和基本使用11:09
3TS核心-interface-可选设置和继承11:32
4TS核心-type注解对象类型13:16
5TS核心-字面量类型08:53
6TS核心-类型推论和any类型07:29

小结 ​

  1. 函数类型注解只做两件事:约束参数(含可选参 ?,且必须置于末尾)和约束返回值(无返回值用 void,不是 undefined)。
  2. interface 约束的是对象的精确"形状":属性名、数量、类型三者同时匹配,多一个少一个都不行。
  3. 可选属性 ? 与可选参数 ? 语义一致:可以不给,给了就必须类型正确。
  4. 类型复用的两条路:interface 用 extends,type 用 & 交叉类型;对象注解场景推荐统一用 type,因为它更灵活(还能表达联合、字面量、基础类型别名)。
  5. 同名 interface 会声明合并(属性并集,冲突即报错),同名 type 直接报重复定义——这是选型时要考虑的差异点。
  6. 字面量类型极少单独使用,标准姿势是与联合类型组合,把"任意 string/number"收窄为"有限可选范围",如性别、状态码、按钮 type。
  7. 类型推论是"少写注解"的福利(变量初始化、函数返回值都能推),但空数组/空对象推不出有效类型,必须显式注解;拿不准时把鼠标悬停在变量上查看推断结果。
  8. any 是逃生舱不是常规手段:它关闭检查、丢失提示、还会传染,能写具体类型就不写 any,需要"未知"时用 unknown。所有类型约束只在编译期生效,运行时依然要靠代码自身的防御。