TypeScript(简称 TS)作为 JavaScript 的超集,已成为前端工程化的标配。它通过静态类型检查,提前规避大量运行时错误,让代码更易维护、更具可读性。本文抛开复杂概念,从新手视角梳理 TS 核心基础知识,看完就能上手写 TS 代码。
一、为什么要学 TypeScript?
先明确学习的意义,避免盲目跟风:
- 静态类型检查:编码阶段发现错误(如类型不匹配、属性不存在),而非运行时崩溃;
- 更好的代码提示:VS Code 等编辑器能精准提示变量 / 函数的属性和方法,提升开发效率;
- 代码可读性提升:类型注解就是 "自文档",一眼看懂变量 / 函数的用途;
- 工程化必备:Vue3、React、Node.js 主流框架 / 环境均推荐 / 支持 TS,大厂项目标配。
二、TS 环境搭建(快速上手)
1. 安装 TypeScript
js
# 全局安装 TS 编译器
npm install -g typescript
# 验证安装(查看版本)
tsc -v
2. 第一个 TS 程序
-
创建
hello.ts文件:ts// 类型注解:指定变量类型为字符串 const message: string = "Hello TypeScript!"; console.log(message); -
编译 TS 为 JS:
ts# 将 hello.ts 编译为 hello.js tsc hello.ts -
运行 JS 文件:
tsnode hello.js
3. 简化开发:自动编译 + 热更新(可选)
ts
# 安装 ts-node(直接运行 TS,无需手动编译)
npm install -g ts-node
# 直接运行 TS 文件
ts-node hello.ts
三、核心基础:类型注解与类型推断
1. 类型注解(手动指定类型)
语法:变量名: 类型 = 值,告诉 TS 变量的具体类型。
ts
// 基本类型注解
let name: string = "张三"; // 字符串
let age: number = 25; // 数字(整数/浮点数/NaN/Infinity)
let isAdult: boolean = true; // 布尔值
let empty: null = null; // null
let undef: undefined = undefined; // undefined
// 数组注解(两种写法)
let arr1: string[] = ["苹果", "香蕉"]; // 推荐
let arr2: Array<number> = [1, 2, 3]; // 泛型写法
// 对象注解
let user: { name: string; age: number } = {
name: "李四",
age: 30,
};
// 函数注解(参数 + 返回值)
function add(a: number, b: number): number {
return a + b;
}
2. 类型推断(TS 自动推导类型)
TS 会根据变量的初始值自动推断类型,无需手动注解(日常开发中优先用推断,减少冗余)。
typescript
运行
ts
let str = "hello"; // TS 自动推断 str 为 string 类型
str = 123; // 报错:不能将类型"number"分配给类型"string"
let num = 100; // 推断为 number 类型
let bool = false; // 推断为 boolean 类型
核心原则:能靠推断的就不手动注解,需要明确约束时才加注解。
四、常用基础类型
1. 原始类型
表格
| 类型 | 说明 | 示例 |
|---|---|---|
string |
字符串 | let str: string = "TS" |
number |
数字 | let num: number = 666 |
boolean |
布尔值 | let flag: boolean = false |
null |
空值 | let n: null = null |
undefined |
未定义 | let u: undefined = undefined |
symbol |
唯一值 | let s: symbol = Symbol("id") |
bigint |
大整数 | let b: bigint = 100n |
2. 数组
两种写法,推荐第一种:
ts
// 写法1:类型[]
let numbers: number[] = [1, 2, 3];
// 写法2:Array<类型>
let strings: Array<string> = ["a", "b"];
// 禁止混合类型(除非指定联合类型)
let mix: (string | number)[] = [1, "a"]; // 联合类型:字符串或数字
3. 元组(Tuple)
固定长度、固定类型的数组(强约束):
ts
// 元组注解:第一个元素是string,第二个是number
let tuple: [string, number] = ["张三", 25];
tuple[0] = "李四"; // 合法
tuple[1] = 30; // 合法
tuple.push(3); // 注意:push 不会报错(TS 设计缺陷),但访问 tuple[2] 会报错
4. 任意类型(any)
关闭 TS 类型检查,慎用(失去 TS 核心价值):
ts
let anyValue: any = "hello";
anyValue = 123; // 不报错
anyValue = true; // 不报错
anyValue.foo(); // 不报错(运行时可能崩溃)
5. 未知类型(unknown)
安全版 any,必须先类型校验才能使用:
ts
let unknownValue: unknown = "hello";
// unknownValue.toUpperCase(); // 报错:不能直接调用方法
// 先校验类型,再使用
if (typeof unknownValue === "string") {
unknownValue.toUpperCase(); // 合法
}
6. 空类型(void)
表示函数没有返回值(或返回 undefined):
ts
function logMsg(): void {
console.log("这是一个无返回值的函数");
// 省略 return 或 return undefined 均合法
}
7. 永不类型(never)
表示永远不会发生的值(如抛出错误、无限循环):
ts
// 抛出错误的函数,返回值为 never
function throwError(): never {
throw new Error("出错了!");
}
// 无限循环的函数,返回值为 never
function infiniteLoop(): never {
while (true) {}
}
五、进阶基础:接口与类型别名
1. 接口(interface)
用于约束对象的结构,可扩展、可实现,是 TS 中定义对象类型的核心方式:
ts
// 定义接口
interface User {
name: string; // 必选属性
age: number; // 必选属性
gender?: string; // 可选属性(加 ?)
readonly id: number; // 只读属性(不可修改)
}
// 使用接口约束对象
let user: User = {
name: "张三",
age: 25,
id: 1001,
// gender 可选,可省略
};
user.id = 1002; // 报错:只读属性不能修改
2. 类型别名(type)
给类型起别名,适用范围更广(可约束任意类型,不止对象):
ts
// 基本类型别名
type Str = string;
let str: Str = "hello";
// 对象类型别名
type User = {
name: string;
age: number;
};
// 联合类型别名
type NumberOrString = number | string;
let value: NumberOrString = 100;
value = "abc";
3. interface vs type 核心区别
表格
| 特性 | interface | type |
|---|---|---|
| 扩展 | 可通过 extends 扩展 |
可通过 & 交叉扩展 |
| 重复定义 | 支持(自动合并) | 不支持(会报错) |
| 适用范围 | 主要约束对象 / 类 | 可约束任意类型(基本类型、联合类型等) |
使用建议 :定义对象 / 类的结构用 interface,其他场景用 type。
六、函数相关类型
1. 函数参数与返回值注解
ts
// 普通函数
function sum(a: number, b: number): number {
return a + b;
}
// 箭头函数
const multiply = (a: number, b: number): number => {
return a * b;
};
// 无返回值
const log = (msg: string): void => {
console.log(msg);
};
2. 可选参数与默认参数
ts
// 可选参数(加 ?,必须放在必选参数后面)
function greet(name: string, age?: number): void {
console.log(`姓名:${name},年龄:${age || "未知"}`);
}
greet("张三"); // 合法
greet("李四", 30); // 合法
// 默认参数(自动推断类型,无需加 ?)
function sayHi(name: string = "游客"): void {
console.log(`你好,${name}`);
}
sayHi(); // 输出:你好,游客
3. 函数类型别名
定义函数的 "形状"(参数类型 + 返回值类型):
ts
// 定义函数类型
type AddFn = (a: number, b: number) => number;
// 实现函数
const add: AddFn = (x, y) => {
return x + y;
};
七、类型守卫
通过代码逻辑缩小类型范围,让 TS 更精准推断类型:
ts
// typeof 类型守卫(适用于原始类型)
function printValue(value: string | number) {
if (typeof value === "string") {
console.log(value.toUpperCase()); // TS 知道这里 value 是 string
} else {
console.log(value.toFixed(2)); // TS 知道这里 value 是 number
}
}
// instanceof 类型守卫(适用于类实例)
class Animal {}
class Dog extends Animal {
bark() {
console.log("汪汪汪");
}
}
function judgeAnimal(animal: Animal) {
if (animal instanceof Dog) {
animal.bark(); // TS 知道这里 animal 是 Dog 实例
}
}
八、TS 配置文件(tsconfig.json)
项目中通过 tsconfig.json 配置 TS 编译规则,执行 tsc --init 生成默认配置,核心配置说明:
json
{
"compilerOptions": {
"target": "ES6", // 编译目标 JS 版本(ES5/ES6/ESNext)
"module": "ESNext", // 模块系统(CommonJS/ESModule)
"outDir": "./dist", // 编译后的 JS 文件输出目录
"rootDir": "./src", // 源文件目录
"strict": true, // 开启严格模式(推荐,强制类型检查)
"noImplicitAny": true, // 禁止隐式 any 类型
"esModuleInterop": true // 兼容 CommonJS 和 ESModule
},
"include": ["./src/**/*"], // 要编译的文件
"exclude": ["node_modules"] // 排除的文件
}
九、新手避坑指南
- 不要滥用 any :用
unknown替代 any,保留类型检查; - 可选参数放最后:TS 要求可选参数必须在必选参数之后;
- 元组 push 不报错:元组虽固定长度,但 push 不会触发 TS 报错,需手动规避;
- 严格模式必开 :
strict: true能暴露更多潜在问题,是 TS 核心价值所在; - 类型断言要谨慎 :
as语法是 "告诉 TS 我比你更清楚类型",滥用会导致类型不安全。
总结
- TS 核心是静态类型系统,通过类型注解 / 推断提前规避错误;
- 常用基础类型:原始类型、数组、元组、any/unknown、void/never,需掌握各自使用场景;
- 定义对象结构优先用
interface,其他类型约束用type; - 函数注解要关注参数、返回值、可选参数,类型守卫能提升类型推断精度;
- 项目中务必开启严格模式(
strict: true),发挥 TS 最大价值。
从 JS 过渡到 TS 无需一步到位,可先在项目中局部使用,逐步覆盖,重点是理解 "类型" 的核心思想,而非死记语法。掌握本文的基础知识,足以应对日常开发中 80% 的 TS 场景,后续可再深入泛型、装饰器、高级类型等内容。