TypeScript

技术栈
前端框架
javascripttypedmicrosoftcompilerlanguage

概览

TypeScript 技术栈概览

TypeScript 是由 Microsoft 于 2012 年发布的 JavaScript 超集,由 Anders Hejlsberg(C# 之父)主导设计。它在 JavaScript 基础上添加了静态类型系统,通过编译器在开发阶段检测类型错误,大幅提升大型项目的可维护性。

解决什么问题

  • JS 缺乏类型检查 → 运行时 Bug 频发 → TypeScript 编译期捕获
  • 大型项目难以重构 → 类型系统提供 IDE 智能提示和自动补全
  • 团队协作接口不明确 → Interface/Type 定义契约
  • ES6+ 语法兼容 → TS 编译器自动降级为目标 JS 版本

关键特性

  • 静态类型检查:编译时发现类型错误,避免 undefined is not a function
  • 类型推断:自动推导变量类型,减少显式标注
  • 接口 (Interface) 与 类型别名 (Type):定义数据结构契约
  • 泛型 (Generics):编写可复用的类型安全组件
  • 枚举 (Enum):具名常量集合
  • 装饰器 (Decorator):元编程支持(Angular/NestJS 大量使用)
  • 与 JS 完全兼容.js 重命名为 .ts 即可逐步迁移
  • TSConfig:灵活的编译选项(strict mode、target、module 等)

安装

环境准备

  • Node.js:>= 16.x(推荐 18 LTS 或 20 LTS)
  • npm / pnpm / yarn:任一包管理器
  • 编辑器:VS Code(TypeScript 同为微软出品,支持最佳)

安装命令

全局安装 TypeScript 编译器

# npm
npm install -g typescript

# pnpm
pnpm add -g typescript

# 验证安装
tsc --version

项目本地安装

npm init -y
npm install -D typescript @types/node
npx tsc --init    # 生成 tsconfig.json

tsconfig.json 最小配置

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true,
    "outDir": "./dist",
    "rootDir": "./src"
  },
  "include": ["src/**/*"]
}

编译与运行

npx tsc                    # 编译 src → dist
node dist/index.js         # 运行编译后的 JS

或使用 ts-node 直接运行:

npm install -D ts-node
npx ts-node src/index.ts

常见安装问题

Q1: tsc 不是内部命令

全局安装失败或 PATH 未包含 npm global bin。用 npx tsc 代替,或检查 npm root -g

Q2: 编译报 Cannot find module 'xxx'

缺少 @types/xxx 类型声明。运行 npm install -D @types/xxx;若没有对应包,创建 src/types/xxx.d.ts 手动声明。

Q3: strict 模式报错太多

初学者可将 strict 设为 false,逐步开启 noImplicitAnystrictNullChecks 等子选项。

Q4: ts-node 运行慢

使用 ts-node --swctsx 替代品;生产环境建议先 tsc 编译再 node 运行。

示例

TypeScript 例程:从 JavaScript 到 TypeScript 的类型迁移

目标

展示 TypeScript 核心类型系统:基础类型、Interface、泛型、类型守卫,并对比 JS 常见坑点。

完整代码

// ── 1. 基础类型注解 ──
let username: string = "Alice";
let age: number = 22;
let isStudent: boolean = true;
let scores: number[] = [85, 92, 78];

// ── 2. Interface 定义数据结构 ──
interface User {
  id: number;
  name: string;
  email: string;
  role?: "admin" | "user"; // 可选 + 字面量联合
  createdAt: Date;
}

const user: User = {
  id: 1,
  name: "Bob",
  email: "bob@example.com",
  role: "user",
  createdAt: new Date(),
};
// user.role = "guest";  // ❌ 编译错误!

// ── 3. 泛型函数 ──
function first<T>(arr: T[]): T | undefined {
  return arr[0];
}

const n = first([1, 2, 3]);    // n: number | undefined
const s = first(["a", "b"]);   // s: string | undefined

// ── 4. 类型守卫(Type Guard) ──
function process(input: string | number): string {
  if (typeof input === "string") {
    return input.toUpperCase(); // 此处 TypeScript 知道 input 是 string
  }
  return input.toFixed(2);      // 此处 TypeScript 知道 input 是 number
}

console.log(process("hello")); // "HELLO"
console.log(process(3.1415));  // "3.14"

// ── 5. 工具类型 Utility Types ──
type ReadonlyUser = Readonly<User>;
type UserSummary = Pick<User, "id" | "name">;

const partial: Partial<User> = { name: "Temp" }; // 所有字段可选

// ── 6. JS 常见坑 → TS 捕获 ──
const obj = { x: 10 };
// console.log(obj.y.toFixed());  // ❌ TS 编译期就报错,而不是运行时

运行步骤

npm install -D typescript ts-node
npx ts-node index.ts

预期输出

HELLO
3.14

关键要点

JS 痛点 TS 解决方案
运行时才报错 编译期捕获
参数无类型约束 类型注解
无法知道对象结构 Interface/Type
any 满天飞 strict: true 禁止隐式 any

教程

TypeScript 入门到进阶教程

第一章:为什么要学 TypeScript

JavaScript 是动态类型语言——变量类型在运行时确定。这带来灵活性,但在大型项目中是灾难:

  • 重构一个函数签名,不知道哪些调用会炸
  • 后端返回的数据结构,只能靠注释来约定
  • undefined is not a function 是最常见的运行时错误

TypeScript 在 JS 之上加了类型系统,编译后就变成了干净的 JS。你可以把它理解成「带类型检查的 JS」。

第二章:核心类型一览

2.1 基础类型

let isDone: boolean = false;
let decimal: number = 6;
let color: string = "blue";
let list: number[] = [1, 2, 3];
let tuple: [string, number] = ["hello", 10]; // 元组

2.2 枚举

enum Direction {
  Up = "UP",
  Down = "DOWN",
  Left = "LEFT",
  Right = "RIGHT",
}

2.3 any / unknown / never

  • any:关闭类型检查(尽量不用)
  • unknown:安全版 any,必须先类型守卫才能使用
  • never:永远不会到达(抛异常、死循环)

2.4 类型断言

const el = document.getElementById("app") as HTMLDivElement;

第三章:Interface vs Type

两者大部分场景可互换,但有细微差别:

Interface Type
扩展方式 extends & 交叉
声明合并 同名自动合并 报错
能用联合
官方推荐 优先 Interface 需要联合/交叉时用 Type

第四章:泛型

泛型让你写出可复用的类型安全代码:

function identity<T>(arg: T): T { return arg; }

interface ApiResponse<T> {
  data: T;
  code: number;
  message: string;
}

第五章:工程化进阶

5.1 tsconfig.json 关键配置

  • strict: true —— 开启所有严格检查(强烈推荐)
  • paths —— 路径别名
  • declaration: true —— 生成 .d.ts

5.2 声明文件

为无类型的 JS 库写 .d.ts

declare module "my-js-lib" {
  export function doStuff(x: number): string;
}

5.3 与主流框架集成

  • React.tsx + @types/react
  • Vue 3:原生 TS 支持,defineProps<T>()
  • Node.js@types/node
  • Express@types/express

思考题

  1. anyunknown 的区别是什么?什么时候该用 unknown
  2. 为什么 Readonly<User> 能工作?TypeScript 内部是怎么实现的?
  3. 大型 JS 项目如何渐进式迁移到 TS?分几步?

参考资料

暂无参考文献