Node.js 开发手册NODE.JS

CHAPTER 08工程层 · TYPESCRIPT

TypeScript 工程化

tsconfig、类型系统、与 Node 集成、装饰器、tsx/ts-node 与类型安全 API。用类型把 bug 挡在编译期。

开始阅读难度进阶先修前七章约2小时
08.1

为什么用 TS

TypeScript 给 JS 加静态类型,在编译期发现"传错类型""访问不存在字段"等问题,重构更安心。它最终编译为纯 JS 运行。

类型即文档

函数签名里的类型本身就是最好的文档,配合 IDE 自动补全,新成员上手更快。

08.2

核心类型

基础类型、接口、联合类型、字面量类型、可选/只读修饰符,构成日常建模工具箱。

type Role = 'admin' | 'user';
interface User {
  id: number;
  email: string;
  role: Role;
  nickname?: string;        // 可选
  readonly createdAt: Date; // 只读
}
08.3

泛型与收窄

泛型让函数/类型参数化;类型守卫(typeof/instanceof/in 或自定义 is)把宽类型收窄成具体类型。

function first(arr: T[]): T | undefined { return arr[0]; }

function isUser(u: unknown): u is User {
  return typeof u === 'object' && u !== null && 'email' in u;
}
if (isUser(x)) console.log(x.email);  // 此处 x 已被收窄为 User
08.4

tsconfig 配置

Node 项目的 tsconfig 应开启 strict,并正确设置模块/目标以匹配 Node 20 的 ESM。

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "strict": true,
    "outDir": "dist",
    "rootDir": "src"
  },
  "include": ["src"]
}
08.5

运行 TS

开发期用 tsx(基于 esbuild,免编译即时运行)或 ts-node;生产期先用 tsc 编译到 dist 再跑 JS。

npx tsx src/index.ts          # 开发热运行
npm run build                 # tsc 输出到 dist
node dist/index.js            # 生产运行编译产物
生产别跑源码

线上运行编译后的 JS,启动更快、无编译开销、依赖更干净。

08.6

装饰器

装饰器(TS 5 稳定语法)可标注类、方法、参数,NestJS 等框架大量使用它声明路由与注入。

function Log(target: any, key: string, desc: PropertyDescriptor) {
  const fn = desc.value;
  desc.value = function (...args: any[]) {
    console.log('call', key, args);
    return fn.apply(this, args);
  };
}
class Svc { @Log greet(n: string) { return `hi ${n}`; } }
08.7

运行时校验 zod

TS 类型只在编译期存在。外部输入(HTTP body、env)需用 zod 在运行时校验,并推导出类型。

import { z } from 'zod';
const UserSchema = z.object({ email: z.string().email(), age: z.number().int() });
type User = z.infer;   // 类型由 schema 推导

const data = UserSchema.parse(req.body);  // 失败抛错,成功为 User 类型
信任边界

任何来自网络/配置的数据都应经运行时校验,不要把外部输入当已类型化的值直接用。

08.8

常见陷阱与 FAQ

any 太多怎么办?

开启 strict 与 noImplicitAny,逐步把 any 换成具体类型或 unknown + 守卫。any 会"关掉"类型检查,是隐患。

类型与运行时校验重复吗?

职责不同:TS 类型管编译期;zod 管运行时边界。用 z.infer 让两者同源,避免漂移。

tsx 能上生产吗?

不建议。tsx/ts-node 适合开发;生产编译成 JS 运行更稳更快。

08.9

实战练习与资源

延伸资源