环境搭建与初体验

安装工具、配置编译器、写出第一个 .ts 文件

🎯 学习目标

学完本章,你将能够:

  • 能够独立完成 TypeScript 开发环境搭建(Node.js、tsc、tsconfig)
  • 能够理解 tsconfig.json 核心配置项的作用与推荐设置
  • 能够使用 tsc 编译 TS 文件并用 tsx 直接运行
  • 能够配置 ESLint 与 VS Code 实现开发体验优化
  • 能够解决常见的环境配置问题与模块解析错误

怎么开始

浏览器不认识 .ts 文件,那 TypeScript 代码怎么运行?

答案很简单:先把 .ts 编译成 .js,然后像平时一样运行。

你需要三样东西:一个编译器(tsc)、一个配置文件(tsconfig.json)、一个能直接运行 TS 的工具(tsx)。

Part 1: 安装编译器

TypeScript 编译器是一个 npm 包,装好就能用

浏览器不认识 .ts 文件,那 TypeScript 代码怎么运行?答案是先编译成 JS。你需要一个编译器——tsc,还有开发时直接运行 TS 的工具 tsx。这一节只需要几行命令,把编译环境搭起来。安装完成后,你的终端就能识别 .ts 文件了。

全局安装

最简单的方式,一行命令搞定

$ npm install -g typescript
$ tsc --version
Version 5.4.5

安装完成后,tsc 命令全局可用。但更推荐项目本地安装,方便团队统一版本。

项目本地安装

推荐方式,团队协作版本一致

$ npm install -D typescript
$ npx tsc --version

# 同时安装 tsx 用于直接运行 TS 文件
$ npm install -D tsx

# 直接运行 TS 文件
$ npx tsx src/index.ts
包名用途安装命令
typescriptTS 编译器npm i -D typescript
tsx直接运行 TS 文件npm i -D tsx
ts-nodeTS 执行引擎npm i -D ts-node
@types/nodeNode.js 类型定义npm i -D @types/node

tsx 比 ts-node 快得多(基于 esbuild),推荐新项目使用 tsx。

Part 2: 配置文件

tsconfig.json 告诉编译器怎么编译你的代码

编译器装好了,但它怎么知道你的源码在哪、编译输出放哪、要不要开严格模式?这些全写在 tsconfig.json 里。一行命令就能生成它,但里面那些配置项到底是什么意思?这一节从"开箱即用"到"理解每一行配置",帮你彻底搞懂 tsconfig。

tsconfig 速览

一条命令生成,几个关键选项就够了

$ npx tsc --init
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "sourceMap": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}

strict 严格模式

一行配置开启所有严格检查

"strict": true 等于同时开启以下所有检查:

选项作用
strictNullChecksnull/undefined 不能赋值给其他类型
noImplicitAny禁止隐式 any
strictFunctionTypes函数参数类型严格协变
strictPropertyInitialization类属性必须初始化
noImplicitThis禁止隐式 this
alwaysStrict始终严格模式解析
建议:始终开启 strict 模式。虽然初期会多写一些类型,但能避免大量运行时错误。

tsconfig 进阶配置

理解几个关键选项,让配置不再"复制粘贴"。

模块解析策略

moduleResolution 决定 TS 怎么找 import 的文件

模式行为适用场景
"node"按 Node.js 的规则解析,支持目录下的 index旧项目、CommonJS 模块
"node16"Node.js 16+ 的精确解析,要求写明扩展名Node.js ESM 项目
"bundler"兼容 Vite/webpack 等打包工具的解析规则前端项目、用 tsx 运行的项目
// bundler 模式下可以省略扩展名
import { User } from "./types/user";    // bundler ✅  node16 ❌

// node16 要求写明 .js 扩展名(即使源文件是 .ts)
import { User } from "./types/user.js"; // node16 ✅
初学者建议:用 tsx 运行的 Node.js 项目选 "bundler",最省心。如果用纯 Node.js 运行 ESM,选 "node16"。

其他重要选项

每个选项解决一个具体问题

{
  "compilerOptions": {
    "verbatimModuleSyntax": true,
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true,
    "noEmit": false
  }
}
选项作用什么时候开
verbatimModuleSyntax强制用 import type 导入纯类型,确保 tree-shaking 生效推荐始终开启
declaration生成 .d.ts 类型声明文件写库给别人用时
declarationMap为 .d.ts 生成 sourceMap,方便从使用方跳回源码库作者调试时
sourceMap生成 .js.map 文件,浏览器/调试器能对应回 .ts 源码需要断点调试时

verbatimModuleSyntax 的好处:它强制你区分"值导入"和"类型导入",打包工具就能安全地移除只用作类型的 import,减小最终产物体积。

实战 tsconfig

一个 Node.js 后端项目的推荐配置

{
  "compilerOptions": {
    // 语言与模块
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "bundler",

    // 输出
    "outDir": "./dist",
    "rootDir": "./src",
    "sourceMap": true,

    // 严格检查
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,

    // 模块互操作
    "esModuleInterop": true,
    "verbatimModuleSyntax": true,
    "isolatedModules": true,
    "resolveJsonModule": true,

    // 加速
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}
注意:noUnusedLocals 和 noUnusedParameters 会在有未使用变量时报错。如果你正在快速原型开发,可以暂时关掉这两个。

@types 类型生态

第三方库没有 TS 类型怎么办?

JavaScript 生态有大量第三方库,不是所有库都自带 TypeScript 类型。这时候需要 DefinitelyTyped 社区提供的类型包。

# 搜索某个库有没有类型包
$ npm info @types/lodash
# 有输出说明存在这个类型包

# 常见的 @types 包
$ npm install -D @types/node        # Node.js API 类型
$ npm install -D @types/express     # Express 框架类型
$ npm install -D @types/jest        # Jest 测试框架类型
$ npm install -D @types/react       # React 类型
情况怎么办例子
库自带 TS 类型直接用,不用装 @typeszod、prisma
有 @types/xxx安装对应的 @types 包@types/express
啥都没有自己写 .d.ts 声明文件内部自研库
// types/shims.d.ts —— 给没有类型的库写声明
declare module "some-untyped-lib" {
    export function doSomething(input: string): number;
}

DefinitelyTyped(github.com/DefinitelyTyped)是最大的社区类型仓库,几乎主流 JS 库都能在上面找到类型定义。当你 npm install 一个库后,VS Code 提示"任何",就去查查有没有 @types 包。

ESLint + TypeScript

tsc 只管类型检查,代码风格和潜在问题还得靠 ESLint。

配置 ESLint

安装与基本配置,五分钟搞定

$ npm install -D eslint @eslint/js typescript-eslint
// eslint.config.mjs(ESLint 9+ 扁平配置)
import eslint from "@eslint/js";
import tseslint from "typescript-eslint";

export default tseslint.config(
    eslint.configs.recommended,
    ...tseslint.configs.recommended,
    {
        rules: {
            // 允许 any 但要求显式声明(不忽略)
            "@typescript-eslint/no-explicit-any": "warn",
            // 未使用的变量报错(排除下划线前缀)
            "@typescript-eslint/no-unused-vars": [
                "error",
                { argsIgnorePattern: "^_" }
            ],
            // 强制用 import type 导入类型
            "@typescript-eslint/consistent-type-imports": "error"
        }
    }
);
为什么还要 ESLint? 因为 tsc 只做类型检查(这是"对不对"),而 ESLint 还能检查未使用的变量、复杂度过高的函数、不一致的导入风格等(这是"好不好")。两者互补,不冲突。

运行 ESLint

命令行跑一遍,集成到 scripts 里自动化

# 检查所有 .ts 文件
$ npx eslint src/

# 自动修复能修的问题
$ npx eslint src/ --fix

# 只检查不改
// package.json
{
  "scripts": {
    "dev": "tsx watch src/index.ts",
    "lint": "eslint src/",
    "lint:fix": "eslint src/ --fix",
    "typecheck": "tsc --noEmit",
    "build": "tsc"
  }
}
命令作用何时运行
npm run typechecktsc 类型检查每次提交前 / CI
npm run lintESLint 代码质量检查每次提交前 / CI
npm run lint:fix自动修复 lint 问题开发中随手修

推荐流程:typecheck 管类型对不对,lint 管代码好不好。在 CI 中两个都跑:npm run typecheck && npm run lint。

Part 3: 第一个 .ts 文件

创建一个 TypeScript 文件,体验类型检查的效果

编译器和配置都就绪了,该写点代码了。这一节创建你的第一个 .ts 文件,用接口定义对象形状,给函数参数加类型注解。然后故意写一个类型错误,看看编译器怎么"秒抓"。编译前后对比一下,你会发现类型注解被完全擦除,输出的就是干净的 JS。

编写 hello.ts

接口 + 类型注解 + 故意犯错

// src/hello.ts
interface User {
    name: string;
    age: number;
}

function greet(user: User): string {
    return `Hello, ${user.name}! You are ${user.age} years old.`;
}

const user: User = { name: "张三", age: 25 };
console.log(greet(user));

// 故意制造一个类型错误
// const wrong: User = { name: 42 }; // 报错!name 应该是 string

注意 interface 定义了对象的形状,: string 和 : number 是类型注解。写错了编译器会标红。

编译与运行

三种方式,从慢到快

# 方式1:先编译再运行
$ npx tsc
$ node dist/hello.js

# 方式2:用 tsx 直接运行(推荐开发时用)
$ npx tsx src/hello.ts
# Hello, 张三! You are 25 years old.

# 方式3:编译单个文件
$ npx tsc src/hello.ts --outDir dist

开发时用 tsx 即时运行,发布时用 tsc 编译输出。

编译前后对比

类型注解被完全擦除

源码 (.ts)

const user: User = {
    name: "张三",
    age: 25
};

编译后 (.js)

const user = {
    name: "张三",
    age: 25
};

所有类型注解(: User)在编译后被完全擦除。浏览器和 Node.js 看到的还是纯 JavaScript。

tsx 快捷运行

开发时的最佳搭档

# 直接运行 TS 文件
$ npx tsx src/index.ts

# 监听模式——文件变化自动重新运行
$ npx tsx watch src/index.ts
// package.json 中的脚本配置
{
  "scripts": {
    "dev": "tsx watch src/index.ts",
    "build": "tsc",
    "start": "node dist/index.js"
  }
}
# tsx 还提供交互式 TS REPL
$ npx tsx
> let x: number = 42
> x
42
> x = "hello"  // 报错:不能将 string 赋值给 number

Part 4: VS Code 的 TS 加持

VS Code 对 TypeScript 有一流的内置支持,无需额外装扩展

代码能跑起来了,但每次都要手动编译也太麻烦了。好消息是 VS Code 内置了完整的 TypeScript 支持。输入 . 自动提示属性,按 F2 安全重命名,Ctrl+. 一键修复类型错误。这一节掌握几个关键快捷键和调试配置,让你的 TS 开发效率直接翻倍。

核心快捷键

这些快捷键会让你的 TS 开发效率翻倍

功能快捷键说明
跳转到定义F12跳到变量/函数/类型的定义位置
查看引用Shift+F12查看哪些地方使用了它
重命名符号F2安全重命名,所有引用自动更新
悬停查看类型鼠标悬停显示完整类型信息
自动补全Ctrl+Space智能提示属性、方法
快速修复Ctrl+.自动修复类型错误
错误面板Ctrl+Shift+M查看所有类型错误

实用技巧

几个让开发更顺畅的小窍门

// 1. 内联查看类型:Ctrl+Shift+点击类型名
// 不跳转文件就能看接口的完整定义

// 2. 自动导入:输入变量名后 Ctrl+. 自动添加 import

// 3. 重构提取:选中代码后 Ctrl+Shift+R
// - 提取函数 / 提取接口 / 提取类型别名

// 4. 选择 TS 版本
// Ctrl+Shift+P → "TypeScript: Select TypeScript Version"
类型检查不生效? 按 Ctrl+Shift+P,输入 TypeScript: Restart TS Server 重启 TypeScript 服务。

快速修复技巧

用 Ctrl+. 解决大部分类型报错

光标放在报错的位置,按 Ctrl+.,VS Code 会弹出可用的修复方案:

问题快速修复方案
缺少某个属性自动添加缺失的属性到对象
类型不匹配建议添加类型断言或修改类型
找不到模块自动添加 import 语句
未使用的导入删除未使用的 import
函数缺少返回类型推断并添加返回类型注解
# 批量操作也很方便:
# Ctrl+Shift+P → "Add all missing imports"
# 一次性给整个文件补全所有缺失的 import

# Ctrl+Shift+P → "Organize imports"
# 排序 import 语句 + 删除未使用的导入

养成习惯:看到红色波浪线,先按 Ctrl+. 看看编辑器能不能帮你修。大部分时候一个回车就搞定了。

调试与配置

断点调试 TS + 切换 TS 版本 + 内联提示

断点调试 .ts 文件:需要 sourceMap: true,然后直接在 .ts 文件里打断点。

// .vscode/launch.json —— 用 tsx 调试当前文件
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Debug TS",
      "type": "node",
      "request": "launch",
      "runtimeExecutable": "npx",
      "runtimeArgs": ["tsx", "${file}"],
      "console": "integratedTerminal"
    }
  ]
}

内联提示(Inlay Hints):在编辑器里直接显示参数名和类型推断结果。

// .vscode/settings.json
{
  "typescript.inlayHints.parameterNames.enabled": "all",
  "typescript.inlayHints.functionLikeReturnTypes.enabled": true,
  "typescript.inlayHints.variableTypes.enabled": true
}

切换 TS 版本:Ctrl+Shift+P → TypeScript: Select TypeScript Version → 选择工作区版本。这个在升级 TS 版本后特别有用。

调试没命中断点? 检查 tsconfig.json 里 sourceMap 是否为 true,以及 rootDir 和 outDir 配置是否正确。

项目目录

一个规范的 TS 项目长什么样?

my-ts-project/
├── src/                  # 源码目录(.ts 文件放这里)
│   ├── index.ts          # 入口文件
│   ├── utils/            # 工具函数
│   │   └── format.ts
│   └── types/            # 类型定义
│       └── user.ts
├── dist/                 # 编译输出(自动生成,不要手动改)
│   └── index.js
├── types/                # 全局类型声明(.d.ts)
│   └── global.d.ts
├── tsconfig.json         # TS 编译配置
├── package.json
└── node_modules/

用人话说:src/ 是你的工作区,dist/ 是编译器的输出区。types/ 存放共享的类型定义,相当于项目的"合同"。记住——永远不要手动编辑 dist/ 里的文件。

编译全流程

从 .ts 到运行结果,中间经历了什么?

图:TypeScript 编译流程
# 完整流程:先编译,再运行
$ npx tsc            # src/hello.ts → dist/hello.js
$ node dist/hello.js  # 运行编译后的 JS

# 快捷流程:tsx 一条命令搞定
$ npx tsx src/hello.ts  # 编译 + 运行,一步到位
方式命令输出文件适用场景
tsc + node两步执行有 .js 输出生产部署
tsx一步执行无中间文件本地开发

开发工具对比

tsx watch vs tsc --watch vs nodemon,该选哪个?

工具作用文件监听速度推荐场景
tsx watch直接运行 TS + 监听文件变化自动重启极快TS 项目开发首选
tsc --watch监听并编译 TS文件变化自动编译中等需要查看编译输出时
nodemon监听 JS 变化重启需配合 tsc 使用较慢旧 JS 项目迁移
// package.json 中推荐的 scripts 配置
{
  "scripts": {
    "dev": "tsx watch src/index.ts",
    "build": "tsc",
    "typecheck": "tsc --noEmit",
    "start": "node dist/index.js"
  }
}

typecheck 脚本只做类型检查不输出文件,适合在 CI/CD 中使用。dev 用 tsx watch 开发体验最丝滑。

综合练习

创建一个多文件 TS 项目,体验 import/export

// src/types/user.ts —— 定义类型
export interface User {
    id: number;
    name: string;
    email: string;
    role: "admin" | "member";
}

export interface ApiResponse {
    code: number;
    data: T;
    message: string;
}
// src/utils/format.ts —— 工具函数
import type { User } from "../types/user.js";

export function formatUser(user: User): string {
    return `[${user.role}] ${user.name} <${user.email}>`;
}

export function createGuest(): User {
    return { id: 0, name: "访客", email: "", role: "member" };
}
// src/index.ts —— 入口文件
import type { User, ApiResponse } from "./types/user.js";
import { formatUser, createGuest } from "./utils/format.js";

const guest = createGuest();
const response: ApiResponse = {
    code: 200,
    data: guest,
    message: "ok"
};
console.log(formatUser(response.data));

期望输出

$ npx tsx src/index.ts
[member] 访客 <>

常见环境问题

遇到红色报错不要慌。 大部分问题都是配置或路径问题,按下面的步骤逐一排查。

问题一:tsc --version 提示"命令未找到"

原因:TypeScript 没有全局安装,或不在 PATH 中。

修复:用项目本地安装 npm i -D typescript,然后 npx tsc。

问题二:VS Code 里 .ts 文件没有类型提示

原因:项目根目录缺少 tsconfig.json。

修复:运行 npx tsc --init 生成配置文件。

问题三:npx tsx 运行报模块找不到

原因:没有安装 tsx,或路径写错了。

修复:npm install -D tsx,确认文件路径正确。

试一试

练习一

任务:创建一个 TS 项目,编译并运行。

$ mkdir ts-demo && cd ts-demo
$ npm init -y
$ npm install -D typescript tsx
$ npx tsc --init
// 创建 src/index.ts
const message: string = "Hello, TypeScript!";
console.log(message);
$ npx tsx src/index.ts

期望输出

Hello, TypeScript!

练习二

任务:在 hello.ts 中故意写一个类型错误,观察编译器的报错信息。

// 试试这行代码,看看编译器怎么提示
const wrong: number = "hello";

参考答案

error TS2322: 不能将类型"string"分配给类型"number"。

📝 要点总结

本章核心知识点

安装方式

全局安装 tsc,项目本地安装 typescript 依赖

tsconfig

strict、module、target、moduleResolution 核心选项

编译运行

tsc 编译 JS,tsx/ts-node 直接运行 TS

类型生态

@types/* 包提供第三方库类型定义

开发工具

ESLint + Prettier + VS Code 插件提升效率

下一章

环境准备好了,下一章学习基础类型注解——给变量、数组、对象标注类型。

1 / X