TypeScript 语言完整入门指南

2026/07/013 分钟阅读1,048

TypeScript(简称 TS)是 JavaScript 的一个超集,它在 JavaScript 的基础上添加了静态类型系统和面向对象特性。TypeScript 代码不能直接被浏览器或 Node.js 执行,需要编译(Transpile)成标准的 JavaScript 代码后方可运行。它的核心价值在于“在编译期(而不是运行期)发现 Bug”。


1. TypeScript 简介与环境搭建

1.1 核心价值

  • 编译期类型检查:在代码写完保存的那一刻,如果有参数传错、变量名写错,IDE 和编译器会立刻报错,避免带到线上。
  • 极佳的智能提示 (Autocompletion):有了类型定义,你可以轻松看到对象的属性和方法提示,不需要去翻文档。
  • 安全重构:当你要修改一个底层的字段名字,编译器会自动找出全项目所有用到该字段的地方并报错,提示你进行修改,避免漏改。

1.2 环境搭建

  1. TS 的编译需要 Node.js 运行环境支持。
  2. 全局安装 TS 编译器 (tsc):
    npm install -g typescript
  3. 验证安装:
    tsc -v
  4. 本地极速运行工具 (ts-node): 正常开发需要先 tsc file.ts 生成 JS 才能跑。本地测试可以使用 ts-node 直接跳过编译步骤运行:
    npm install -g ts-node
    ts-node file.ts

2. 基础类型注解 (Type Annotation)

TS 的核心是在变量后使用 : Type 语法声明类型。

// 1. 基础基本类型
const username: string = "Bob";
const age: number = 27;
const isActive: boolean = true;

// 2. 数组类型 (两种写法)
const scores: number[] = [95, 88, 76];
const fruits: Array<string> = ["apple", "orange"];

// 3. 元组 (Tuple - 长度固定、类型确定的特殊数组)
const userRole: [number, string] = [1, "admin"];

// 4. 枚举 (Enum)
enum Status {
    Pending, // 默认从 0 开始
    Success, // 1
    Failed   // 2
}
const currentStatus: Status = Status.Success;

3. 接口 (Interface) 与 类型别名 (Type Alias)

当需要声明复杂的对象结构时,可以使用 interfacetype

3.1 接口 (Interface)

用于定义对象(Object)的结构规范:

interface User {
    id: number;
    name: string;
    email: string;
    phone?: string;     // 问号 ? 表示该属性是可选的 (Optional)
    readonly created: Date; // 只读属性,赋值后不可修改
}

const u: User = {
    id: 1,
    name: "Alice",
    email: "alice@example.com",
    created: new Date()
};
// u.created = new Date(); // 报错:只读属性不可修改

3.2 类型别名 (Type)

typeinterface 更灵活,可以定义任意类型(包括联合类型、交叉类型):

type ID = string | number; // 联合类型 (ID 可以是 string 或 number)

let userId: ID = 123;
userId = "usr_999"; // 合法

type UserWithRole = User & { role: string }; // 交叉类型 (合二为一)

4. 函数类型定义

TS 允许你对函数的输入参数和返回值进行强类型约束:

// 限制参数 x, y 必须是数字,且返回值必须是数字
function add(x: number, y: number): number {
    return x + y;
}

// 箭头函数类型定义 (不返回值使用 void)
const logMessage = (msg: string): void => {
    console.log(msg);
};

5. 泛型 (Generics)

泛型是指在定义函数、接口或类时不预先指定具体类型,而是在使用时才动态确定类型的设计模式,是编写可复用代码的核心。

// <T> 代表占位符类型,接收什么类型,返回值就是什么类型
function identity<T>(arg: T): T {
    return arg;
}

// 明确传入数字类型,此时 T 被替换为 number
let output1 = identity<number>(100);

// 传入字符串,T 被替换为 string
let output2 = identity<string>("hello");

6. 进阶工具类型 (Utility Types)

TS 官方内置了一套转换现有类型的工具,非常常用:

interface Todo {
    id: number;
    title: string;
    description: string;
}

// 1. Partial<T> : 将所有属性变成可选
type OptionalTodo = Partial<Todo>; // 属性全部带上问号 ?

// 2. Pick<T, Keys> : 仅拣选出一部分属性组成新类型
type SimpleTodo = Pick<Todo, "id" | "title">; // 只有 id 和 title

// 3. Omit<T, Keys> : 排除掉某些属性后组成新类型
type CustomTodo = Omit<Todo, "description">; // 排除掉 description

7. 配置文件 tsconfig.json

TS 项目的根目录下通常会有一个 tsconfig.json 文件,用于控制编译器的编译规则。

{
  "compilerOptions": {
    "target": "es2022",           // 编译出的 JS 语法标准
    "module": "commonjs",         // 模块规范
    "strict": true,               // 开启所有严格类型检查 (最关键)
    "esModuleInterop": true,      // 兼容 ES 模块导入
    "skipLibCheck": true,         // 跳过对第三方声明文件的类型检查
    "forceConsistentCasingInFileNames": true
  }
}

在现代开发中(特别是使用 Next.js 框架时),脚手架会自动帮你生成并管理好该配置文件。


💡 经典避坑与抓虫小测验

以下小测验选取了 TypeScript 类型系统中最具欺骗性、最容易混淆的规则陷阱。请尝试阅读并分析以下代码,预测其编译结果或找出 Bug,点击“答案与解析”查看具体原因。

测验 1:对象字面量的“双标”类型检查

【题目】:以下这段 TS 代码中,第 15 行和第 18 行的赋值哪一行能通过编译?为什么?

interface User {
    name: string;
    age: number;
}

const info = {
    name: "Bob",
    age: 30,
    email: "bob@example.com" // 多了一个 email 属性
};

// 赋值 1
const u1: User = info;

// 赋值 2
const u2: User = {
    name: "Bob",
    age: 30,
    email: "bob@example.com"
};
👉 答案与解析

【编译结果】: * 赋值 1:可以通过编译,运行完全正常。 * 赋值 2:编译报错:Type '{ name: string; age: number; email: string; }' is not assignable to type 'User'. Object literal may only specify known properties, and 'email' does not exist in type 'User'.

【原因分析】

额外属性检查(Excess Property Checking)

对于赋值 2

对象字面量

对于赋值 1

info
info
u1

结构化类型系统(Structural Typing)

info
User
name
age

测验 2:anyunknown 的防线

【题目】:以下代码中,哪一行会编译报错?说明 anyunknown 的核心区别。

let valueAny: any = "hello";
let valueUnknown: unknown = "hello";

// 行 5
valueAny.trim();

// 行 8
valueUnknown.trim();
👉 答案与解析

【编译结果】: * 行 5:可以通过编译,运行完全正常。 * 行 8:编译报错:'valueUnknown' is of type 'unknown'.

【原因分析】

any

any

unknown

类型安全的 any

unknown

类型守卫(Type Guard)

修改方法

typescript   if (typeof valueUnknown === "string") {       valueUnknown.trim(); // 类型收窄为 string,编译通过   }

测验 3:同名接口(Interface)的自动合并陷阱

【题目】:预测以下代码的编译结果:

interface Window {
    title: string;
}

interface Window {
    width: number;
}

const w: Window = {
    title: "Vibe Platform",
    width: 1024
};
👉 答案与解析

【编译结果】: 完全可以通过编译。

【原因分析】

同名的 interface

合并(Declaration Merging)

Window
title
width

注意点

type
type
Duplicate identifier

测验 4:数字枚举(Enum)的双向通道漏洞

【题目】:以下这段代码能否正常编译运行?如果能,最终会输出什么?

enum Direction {
    Up = 1,
    Down = 2
}

console.log(Direction[1]);
console.log(Direction["Up"]);
👉 答案与解析

【输出结果】

"Up"
1

【原因分析】: 在 TypeScript 中,数字型枚举支持反向映射(Reverse Mapping)。编译成 JS 后,它的数据结构其实被写成了双向的:

var Direction;
(function (Direction) {
    Direction[Direction["Up"] = 1] = "Up";
    Direction[Direction["Down"] = 2] = "Down";
})(Direction || (Direction = {}));
"Up"
1
1
"Up"

避坑警告

Up = "UP"

不支持

undefined
type Direction = "UP" | "DOWN"