第1章:开篇 —— TypeScript、JavaScript 与开发环境
约 4 分钟 · 更新于 2026-09-01
第1章:开篇 —— TypeScript、JavaScript 与开发环境
本章先建立最重要的边界:TypeScript 不会取代 JavaScript,它在代码运行前提供静态分析,随后擦除类型并输出 JavaScript。完成后,你将能创建、检查、编译并运行第一个严格模式项目。
一、TypeScript 为什么出现
JavaScript 最初适合在网页中编写小型交互脚本,后来进入服务器、桌面端、移动端和大型前端应用。代码规模扩大后,一些问题会反复出现:
- 对象属性名拼错,要到运行相关路径时才暴露。
- 函数参数含义只能依赖文档和调用者自觉。
- 重构时很难确认所有调用点是否同步修改。
- IDE 缺少稳定的类型信息,补全和跳转能力受限。
- 多人协作时,同一份数据结构容易产生不同理解。
TypeScript 的解决方案不是重新设计一套运行时,而是给 JavaScript 增加静态类型分析。
二、准确定位:静态类型检查器
可以把 TypeScript 理解为三部分:
- JavaScript 语法与运行时模型:对象、闭包、原型、Promise、事件循环仍然属于 JavaScript。
- 类型系统:描述值的形状、函数契约和类型之间的关系。
- 编译工具链:检查代码,并根据目标环境输出 JavaScript。
ts
function greet(name: string): string {
return `你好,${name}`;
}
greet("TypeScript");
greet(42); // 编译期错误
编译后,类型标注会被移除:
js
function greet(name) {
return `你好,${name}`;
}
类型擦除
string、接口、类型别名和大部分类型运算只存在于检查阶段。运行中的 JavaScript 不会自动保留这些类型,也不会因为你写了 User 就验证网络返回值。
三、TypeScript 是 JavaScript 的类型化超集
“超集”至少包含三层意思:
- 语法层:普通 JavaScript 可以逐步进入 TypeScript 项目。
- 类型层:TypeScript 添加类型标注和分析规则。
- 运行时层:TypeScript 原则上保持 JavaScript 的运行行为,不创造一套独立标准库。
因此,学习 TypeScript 不能跳过 JavaScript。以下主题必须同步理解:
- 对象、数组、函数和闭包
- this 的绑定规则
- 原型与类的关系
- 模块系统
- Promise、事件循环和异步错误
- null、undefined、隐式转换与相等比较
四、TypeScript 能做什么,不能做什么
能做
- 在运行前发现属性不存在、参数不兼容、分支遗漏等问题。
- 为编辑器提供补全、导航、重命名和引用查找。
- 用接口、联合类型和泛型表达数据契约。
- 支持大型项目的模块边界、声明文件和增量构建。
- 允许 JavaScript 项目渐进迁移。
不能做
- 证明业务逻辑一定正确。
- 自动验证 API、数据库或用户输入。
- 消除 JavaScript 的运行时异常。
- 自动解决异步竞态、性能问题或安全漏洞。
- 让错误的 as 断言变成事实。
五、安装与项目初始化
在练习目录中初始化项目:
bash
mkdir ts-start
cd ts-start
npm init -y
npm install --save-dev typescript
npx tsc --init
检查版本:
推荐项目结构:
text
ts-start/
├── package.json
├── tsconfig.json
└── src/
└── index.ts
六、第一个程序
创建 src/index.ts:
ts
interface User {
id: number;
name: string;
}
function describeUser(user: User): string {
return `${user.id}: ${user.name}`;
}
const user = { id: 1, name: "Ada" };
console.log(describeUser(user));
编译:
运行输出的 JavaScript:
七、一个适合学习的 tsconfig.json
json
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"rootDir": "src",
"outDir": "dist",
"strict": true,
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true,
"skipLibCheck": true
},
"include": ["src/**/*.ts"]
}
关键选项:
| 选项 | 作用 |
|---|
| target | 输出 JavaScript 的语言版本 |
| module | 输出和解释模块的方式 |
| rootDir / outDir | 源码与产物目录 |
| strict | 开启严格类型检查组合 |
| noUncheckedIndexedAccess | 索引访问考虑“可能不存在” |
| exactOptionalPropertyTypes | 区分属性缺失与显式 undefined |
| skipLibCheck | 跳过第三方声明文件内部检查以降低成本 |
从 strict: true 开始
新项目不要先关闭严格模式再逐项补债。旧 JavaScript 项目迁移时可以分阶段开启,但应记录最终目标。
八、检查、编译与运行是三件事
bash
npx tsc --noEmit # 只检查,不输出 JavaScript
npx tsc # 检查并输出
npx tsc --watch # 监听修改持续编译
现代前端项目常由 Vite、Webpack、esbuild 或 SWC 转译代码,但它们未必执行完整类型检查。常见做法是:
text
构建工具负责快速转译与打包
TypeScript tsc --noEmit 负责类型检查
测试工具负责行为验证
三者不能互相替代。
九、VS Code 的正确使用方式
VS Code 内置 TypeScript 语言服务,可以提供:
- 类型悬停与签名提示
- 自动导入
- 跳转定义和查找引用
- 安全重命名
- 快速修复
- JavaScript 项目的类型推断
当编辑器和命令行结果不一致时,检查:
- VS Code 使用的 TypeScript 版本是否为工作区版本。
- 当前文件是否被目标 tsconfig.json 包含。
- 是否存在多个相互覆盖的配置文件。
- 构建工具是否只转译而没有类型检查。
十、常见误区
- “TypeScript 是一种能直接运行的 JavaScript”:运行环境通常执行编译后的 JavaScript。
- “有类型就不需要测试”:类型无法验证业务规则和副作用。
- “接口会在运行时校验数据”:接口编译后不存在。
- “到处写 any 也算完成迁移”:any 会关闭关键检查。
- “只要构建成功就说明类型正确”:某些构建工具不会完整检查类型。
- “TypeScript 可以替代 JavaScript 基础”:运行时问题仍需按 JavaScript 规则理解。
十一、实践练习
练习一:观察类型擦除
编写带接口和类型标注的文件,运行 npx tsc,对比 .ts 和 .js,列出被移除的部分。
练习二:制造属性错误
ts
const user = { id: 1, name: "Ada" };
console.log(user.email);
观察编辑器和 npx tsc --noEmit 的诊断。
练习三:区分静态与运行时
从 JSON.parse 得到数据,直接断言为 User,再传入缺少 name 的 JSON。解释为什么编译能通过而运行结果仍然错误。
十二、总结
- TypeScript 是 JavaScript 的静态类型检查器和类型化超集。
- JavaScript 决定运行时语义,TypeScript 主要工作在运行前。
- 类型标注会被擦除,不能替代运行时验证。
- 新项目应优先启用严格模式,并把类型检查与构建、测试分开理解。
- 学习 TypeScript 必须同步掌握 JavaScript。
下一章进入基础语法与常用类型。
请继续阅读:第2章:变量、类型、运算与控制流。
原始资料引用