TypeScript 是什么
这一课你将能做到
- 说清楚 TypeScript 和 JavaScript 的关系(超集、编译、类型擦除)
- 独立完成 TypeScript 的安装、初始化
tsconfig.json、编译运行一个 .ts 文件
- 写出带类型注解的变量、函数,并解释编译期报错与运行时报错的区别
为什么要学
JavaScript 是动态类型语言:变量是什么类型,跑起来才知道。灵活是灵活,但项目一大就出事故——接口返回的字段名写错了、把 null 当对象调方法、把字符串当数字做加法,这些错误统统要等到运行时、甚至是用户点了某个按钮之后才炸出来。
TypeScript 就是给 JavaScript 加一套「类型系统」。人话:你在写代码的时候就声明「这个变量是字符串」「这个函数必须收数字返回布尔」,编辑器当场标红,编译器当场报错,错误从运行时被提前到了编写时。
现实层面的理由更直接:
- 主流前端框架(React / Vue / Next.js)的新项目默认就是 TypeScript
- 大厂前端招聘 JD 里 TypeScript 几乎是必选项
- 面试时「会不会 TS」已经从加分项变成基础项
一句话:不会 TypeScript,现代前端项目你连代码都读不顺。
先建立图像
TypeScript 的整条工作流:
你写的 hello.ts(带类型注解)
│
▼
tsc 编译器检查类型 ──类型有错──▶ 编译失败,报错给你看
│ 类型没错
▼
擦掉所有类型注解,生成 hello.js(纯 JavaScript)
│
▼
浏览器 / Node.js 执行(运行时完全看不到类型的影子)
三个关键词先记住:
| 术语 | 人话解释 |
|---|
| 超集(Superset) | 所有合法 JS 都是合法 TS,TS = JS + 类型 |
| 静态类型 | 写代码时(而非运行时)就确定并检查类型 |
| 类型擦除 | 编译后类型注解全部被删掉,运行时零开销 |
跟着做
步骤 1:安装 TypeScript
确保已装 Node.js(node -v 能输出版本号即可),然后全局安装编译器:
npm install -g typescript
验证安装:
tsc --version
# 输出类似:Version 5.5.3
步骤 2:写第一个 TS 文件
新建文件夹 ts-demo,在里面创建 hello.ts:
// hello.ts
function greet(name: string): string {
return `你好,${name}!`;
}
const message: string = greet("TypeScript");
console.log(message);
注意 : string 就是类型注解——声明参数 name 必须是字符串,返回值也是字符串。
步骤 3:编译并运行
tsc hello.ts
node hello.js
输出:
你好,TypeScript!
打开生成的 hello.js,你会发现类型注解全被擦掉了:
function greet(name) {
return "\u4F60\u597D\uFF0C" + name + "\uFF01";
}
步骤 4:故意制造一个类型错误
function greet(name: string): string {
return `你好,${name}!`;
}
console.log(greet(123)); // 传了数字
再执行 tsc hello.ts,编译器立刻报错:
hello.ts:5:22 - error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'.
关键体验:这个错误在代码运行之前就被拦下了。如果是纯 JavaScript,greet(123) 能正常跑(输出"你好,123!"),但更隐蔽的错误——比如 greet(null) 后续调用 .toUpperCase()——就会在运行时炸。
步骤 5:初始化 tsconfig.json
真实项目不会逐个文件编译,而是用配置文件统一管理:
生成 tsconfig.json(注释很多,先看这几个核心项):
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"strict": true,
"outDir": "./dist",
"rootDir": "./src"
}
}
target:编译成哪个版本的 JS
module:生成什么模块化规范的代码
strict:严格模式总开关,新项目必须开
outDir / rootDir:源码和产物的目录划分
之后直接运行 tsc(不带文件名),就会按配置编译整个项目。
讲清楚要点
- TS 不改变 JS 的运行时行为:类型只在编译期存在,编译产物就是纯 JS,性能零损耗。
- 类型是渐进式的:你可以先给部分代码加类型,慢慢迁移,JS 和 TS 可以共存。
- 报错不等于不能编译:默认情况下
tsc 报错仍可能产出 JS 文件(除非开 noEmitOnError),但报错必须当错误处理,不能无视。
- 编辑器即编译器:VS Code 内置 TS 支持,红色波浪线就是编译器的实时检查,不用每次都跑
tsc。
strict: true 是底线:它一口气打开 strictNullChecks、noImplicitAny 等 8 个严格检查,关掉它等于自废武功。
你可能会懵的地方
-
TS 文件能直接在浏览器里跑吗?
不能。浏览器只认 JavaScript,必须经过编译(tsc)或构建工具(Vite、Next.js 内置)转译。Deno、Bun 这类新运行时可以直接跑 TS,但那是例外。
-
有了 TS 是不是就不会出 bug 了?
不是。TS 只能拦住「类型层面」的错误,逻辑错误(把加写成减)、边界条件、接口数据不符合预期(运行时数据 TS 管不着)照样出 bug。
-
any 是什么?能随便用吗?
any 表示「放弃类型检查」,用了它 TS 就管不了这个变量。初学者常把它当万能解药,这是最差习惯——any 用多了,TS 等于白学。
-
TS 和 JSDoc 注释有什么区别?
JSDoc 也能表达类型,但只是注释约定,没有编译器强制检查。TS 是语言层面的保证。
-
为什么大厂项目文件名一会儿 .ts 一会儿 .tsx?
.tsx 是允许写 JSX(React 组件语法)的 TS 文件。纯逻辑用 .ts,React 组件用 .tsx。
错法对照
| 错法 | 问题 | 正解 |
|---|
变量全标 any | 放弃检查,TS 失去意义 | 写明具体类型,不确定时用 unknown |
| 以为 TS 会在运行时校验数据 | 编译后类型被擦除,接口返回错误数据照样崩 | 运行时校验用 zod 等库(后续课讲) |
全局装完 tsc 就在大项目里手动编译单文件 | 破坏项目构建流程 | 用项目自带的 npm run build / tsc -p . |
新建项目关掉 strict 图省事 | 类型系统形同虚设 | 永远开 strict,遇到报错去修代码 |
把 .ts 文件直接 <script src> 引入 HTML | 浏览器不认 TS 语法 | 先编译成 .js 再引入 |
卡点急救
tsc 命令找不到:全局安装没生效。检查 npm config get prefix 指向的目录是否在 PATH 里;或者在项目里 npm install typescript --save-dev,用 npx tsc 调用。
- 编译报错但生成了 JS:这是默认行为。想严格点,在
tsconfig.json 里加 "noEmitOnError": true。
- VS Code 里类型提示和
tsc 结果不一致:项目装了自己的 TS 版本,编辑器用了内置版本。命令面板执行 TypeScript: Select TypeScript Version → 选 Use Workspace Version。
面试常问
-
TypeScript 和 JavaScript 的区别?
TS 是 JS 的超集,增加了静态类型系统和接口、泛型等语法;TS 需要编译成 JS 才能运行,类型在编译期检查、运行时被擦除。JS 是动态类型,错误暴露在运行时。
-
什么是类型擦除?
TS 编译成 JS 时,所有类型注解、接口、泛型参数都会被删除,运行时不存在任何类型信息。所以 TS 类型零运行时开销,也无法在运行时做类型判断(需要 typeof / 校验库)。
-
any 和 unknown 的区别?
两者都能装任何值,但 any 赋值后可任意调用属性方法、可赋给任何类型(放弃检查);unknown 必须先做类型收窄才能使用(安全)。能用 unknown 就不用 any。
-
为什么项目里要开 strict 模式?
strict 开启空值检查、隐式 any 检查等核心规则,能拦住占比最高的一类线上 bug(null/undefined 访问)。不开 strict 的 TS 项目,类型保障会漏掉大半。
自测三问
- TS 编译产物里还能看到
: string 这样的类型注解吗?为什么?
strictNullChecks 属于哪个配置开关的子项?它拦的是哪类错误?
- 同事说「这个字段类型拿不准,先标
any 吧」,你应该怎么回应?
小结一句话
TypeScript = JavaScript + 编译期类型检查:写代码时声明类型,编译时拦截错误,运行时仍是纯 JS。
延伸