F11第 1 / 1 课时未开始内容版本 1.0.0 · 核验于 2026-10-26

TypeScript 基本类型

TypeScript 基本类型 · 阅读后完成下方实验与检查题,再用「标记完成」记录进度。

学习目标

TypeScript(TS,在 JavaScript 基础上加静态类型的语言,写代码时就能查出类型错误)这一课从「给数据画像」开始:为课程、学习记录和表单定义类型。读完你应该会用 interface/type 描述数据结构,会修可空值与联合类型的报错,并明白为什么不用 any(放弃类型检查的「任意类型」)掩盖问题。

问题场景

课程对象在三个文件里出现:列表页把 c.title 手滑写成 c.titel;详情页对可能为 null 的 c.price 直接调 toFixed(2);报名脚本把 c.hours 写成了字符串。JavaScript 对此全部沉默,直到用户点开那一刻才炸。TS 的价值就在这一步:这些错误在编辑器里画红线,运行之前就拦下。

核心解释

用类型描述数据的样子:

interface Course {
  id: number;
  title: string;
  track: 'foundation' | 'react' | 'nextjs'; // 联合类型:只能是这几个值之一
  price: number | null; // 可空:要么数字,要么 null
  tags?: string[]; // ? 是可选属性,可能不存在
}

const c: Course = {
  id: 1,
  title: '网页基础',
  track: 'foundation',
  price: null, // 合法:但使用前必须处理 null
};

关键规则:可空的值,用之前必须收窄(narrowing,通过判断让类型变具体)。直接写 c.price.toFixed(2) 会报错,因为 price 可能是 null:

function formatPrice(price: number | null): string {
  if (price === null) return '免费';
  return '¥' + price.toFixed(2); // 走过 if,TS 知道这里一定不是 null
}

any 和 unknown 都「什么类型都接受」,但 any 会关掉后续所有检查(方法名打错也不报);unknown 仍然要求你先判断再用。原则:接口边界用 unknown 接住,内部尽快收窄,永远不用 any 兜底。

示例拆解

一个真实流程:读表单输入(类型宽泛)→ 收窄 → 校验 → 使用:

function submitSurvey(raw: FormDataEntryValue | null): string {
  if (typeof raw !== 'string') return '请输入内容'; // 收窄为 string
  const hours = Number(raw);
  if (Number.isNaN(hours)) return '请输入数字';
  return `每天学习 ${hours} 小时`;
}

submitSurvey('3'); // '每天学习 3 小时'
submitSurvey(null); // '请输入内容'
  • FormDataEntryValue 本身是 File | string 的联合,一层 typeof 判断后,后面代码里 raw 就是 string——不写断言,让判断替你说话。
  • 类型标注是「文档 + 检查」双重身份:price: number | null 比注释「可能为空」可靠得多,因为编译器会强制每个使用点处理。
  • 验证方式:故意把 formatPrice(c.price) 改成 c.price.toFixed(2),确认编辑器立刻标红——这就是 TS 在替你跑测试。

动手任务

打开本课实验区:

  1. 给 Course 增加 hours: number,然后故意写 c.hours = '8',读报错信息并用自己的话写在注释里。
  2. 写 totalCost(courses: Course[]): number:免费课(price 为 null)按 0 计,返回总和——不许用 any,也不许用 ! 非空断言。
  3. 把实验区里用 any 掩盖的旧代码改成 unknown,按编译器提示补上收窄,修掉那个 '81' 的输出。

常见错误

  • 用 any 让红线消失:错误只是被藏起来,运行时照炸;类型报错要修类型,不是关检查。
  • 可选属性与可空混淆:tags?: string[] 的值可能是 undefined,访问前同样要判断;price: number | null 则必须显式处理 null。
  • 非空断言滥用:c.price!.toFixed(2) 是「我保证不是 null」的赌注,赌输就是运行时崩溃;能用 if 收窄就不要 !。
  • 以为 TS 会拦截运行时的脏数据:类型只在编译期检查,接口返回的非法数据照样进来;fetch 之后的边界要自己校验(F10、F12 展开)。

检查与复盘

完成下方检查题确认理解。自查清单:

  • 能说清 ?:、| null、any、unknown 四者的区别
  • 处理可空值的默认动作是收窄或默认值,而不是断言
  • 知道类型检查管不到运行时数据,接口边界要另行校验

参考资料

动手实验
动手实验
预览
点击「运行」在隔离沙箱中预览
检查题共 1 题,提交后立即显示解析
答案由服务端判定;答错的题会自动进入复习计划。
Q1单选简单

TypeScript 中写了 let age: number = '18',下面哪句描述正确?

读完这一课了?

标记完成后,工作台会安排接下来的学习。

Command Palette

Search for a command to run...