嘿,朋友!如果你现在正盯着空荡荡的文件夹发愁,或者之前写 TypeScript 总是报错满天飞、配置改到怀疑人生,那这篇教程简直就是为你量身定制的。别担心,我不打算一上来就甩给你一堆看不懂的 JSON 配置,咱们像搭积木一样,一块一块把项目立起来。我会把每一个关键点都掰开了、揉碎了讲清楚,顺便还要教你怎么用代码把项目跑起来。准备好了吗?咱们这就开始。
第一阶段:把地基打好——初始化与核心依赖
首先,咱们得有个地方干活。我在你电脑的某个角落新建了一个文件夹,名字叫 ts-boilerplate。为什么选这个名字?因为它是你的 TypeScript 样板项目,以后你可以基于这个模板快速启动新业务。
打开终端(Terminal 或者 PowerShell),进入这个文件夹,执行以下命令:
cd ts-boilerplate
npm init -y
这一步生成 package.json,它是项目的身份证,记录了你的项目依赖和脚本命令。紧接着,我们需要安装 TypeScript 的核心“三剑客”:
npm install -D typescript @types/node
这里 -D 的意思是 --save-dev,也就是这些依赖只用于开发环境,真正打包上线后它们是不需要的。typescript 是编译器,把你的 .ts 文件翻译成浏览器能懂的 .js;@types/node 则是一些类型声明文件,让你在使用 Node.js API 时能享受到智能提示,不然你连 process 对象都不敢乱用。
安装完别急着写代码,咱们得有个“交通规则”。在项目根目录新建一个文件叫 tsconfig.json。这是 TypeScript 项目的灵魂,没有它,编译器就像没带指南针的船。
{
"compilerOptions": {
"target": "ES2020",
"module": "CommonJS",
"lib": ["ES2020"],
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"declaration": true,
"declarationMap": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
别被这一长串吓到了,我带你逐个拆解,你会发现它们都是些贴心的小配置:
target: “ES2020”:这告诉编译器,我要写出最新的 JavaScript 语法(比如可选链?.、空值合并??),编译器会负责把它们降维兼容到目标环境。选 ES2020 是因为它既现代又广泛支持,不会太激进也不会太陈旧。module: “CommonJS”:因为你可能会用 Node.js,而 Node.js 默认用的是 CommonJS 模块系统(require/module.exports)。如果你是在浏览器端跑前端项目,这里可能要改成ESNext。lib: [“ES2020”]:这是类型检查的基础库。告诉 TypeScript “我知道 ES2020 有哪些全局对象和方法”,不然你写Promise它会报错说找不到类型。outDir&rootDir:这是目录管理的精髓。rootDir是源码所在地(./src),outDir是编译产物输出地(./dist)。分开存放,让项目结构清晰,node_modules和编译后的文件永远不会污染你的源码目录。strict: true:强烈推荐开启! 这是 TypeScript 的“ strict mode”,它会启用一系列严格检查,比如不允许隐式any,强制处理null和undefined。刚开始你会觉得难受,因为编译器总是在挑刺,但相信我,它能帮你杀掉 90% 的运行时错误。esModuleInterop: true:解决模块化之间的兼容性问题。没有它,你import _ from 'lodash'可能会报错,有了它,各种导入方式都能顺滑运行。skipLibCheck: true:跳过对node_modules中.d.ts文件的类型检查。这能显著加快编译速度,因为第三方库的类型定义有时候写得很松散,没必要跟它们较真。declaration: true:生成.d.ts类型声明文件。如果你以后要把这个项目做成 npm 包分享给别人,这个选项是必须的,这样别人用你的库时才有智能提示。include&exclude:明确告诉编译器“只看 src 下面的代码,别碰 node_modules 和 dist”。这能避免编译错误,也能提升性能。
搞定配置后,咱们还得让 npm 能直接运行 TypeScript 代码。打开 package.json,在 scripts 字段中加入:
{
"scripts": {
"dev": "ts-node src/index.ts",
"build": "tsc",
"start": "node dist/index.js"
}
}
ts-node 是个好东西,它允许你直接运行 .ts 文件而无需先编译,非常适合开发阶段的快速调试。如果你还没安装它,记得加上 npm install -D ts-node。
第二阶段:编写代码——从 Hello World 到类型实战
现在,进入重头戏。在 src 目录下新建 index.ts。咱们不写那种无聊的 console.log('Hello World'),咱们写点有型的。
假设我们要做一个简单的用户管理系统,看看 TypeScript 的类型系统能带来什么好处。
// src/index.ts
// 1. 定义接口 (Interface) - 描述对象的形状
interface User {
id: number;
name: string;
age: number;
email: string;
role: 'admin' | 'user'; // 联合类型,只允许这两个值
}
// 2. 定义泛型类 (Generic Class) - 增强复用性
class Repository<T> {
private items: T[] = [];
add(item: T): void {
this.items.push(item);
console.log(`Added ${item}`);
}
getAll(): T[] {
return this.items;
}
}
// 3. 具体的使用者
const userRepo = new Repository<User>();
const newUser: User = {
id: 1,
name: "张三",
age: 28,
email: "zhangsan@example.com",
role: "user"
};
userRepo.add(newUser);
console.log("Current Users:", userRepo.getAll());
这段代码虽然短,但蕴含了 TypeScript 的三大核心支柱:接口、泛型和类型注解。
- 接口
User:它定义了一个契约。如果你少写了email,或者把age写成了字符串,编译器会立马报错告诉你“这里不对劲”。这就是类型安全的力量。 - 泛型
Repository<T>:你看,我不需要为User写一个仓库,为Product写另一个仓库。T是一个占位符,当我实例化new Repository<User>()时,T就变成了User,类型检查自动生效。这让代码极度复用。 - 联合类型
'admin' | 'user':这是一种强约束。比随便传一个字符串'super_admin'要安全得多,防止了拼写错误导致的逻辑漏洞。
运行 npm run dev,你会看到终端打印出你添加的用户信息。这时候,TypeScript 已经在后台默默帮你检查了无数遍潜在的错误。
第三阶段:引入工具链——让开发体验起飞
光能跑起来还不够,咱们得让代码质量可控,让团队协作顺畅。这时候需要引入几个强力工具:eslint 用于代码规范检查,prettier 用于代码格式化。
先安装它们:
npm install -D eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin prettier eslint-config-prettier eslint-plugin-prettier
这些包名看起来很长,别怕,它们的分工很明确:
eslint:核心 lint 工具。@typescript-eslint/*:让 ESLint 能读懂 TypeScript 语法。prettier:代码格式化神器,保证所有人的代码长得都一样。eslint-config-prettier:关掉 ESLint 中和 Prettier 冲突的规则,避免打架。eslint-plugin-prettier:让 ESLint 调用 Prettier 进行格式化检查。
接着,创建配置文件。在项目根目录新建 .eslintrc.json:
{
"root": true,
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint", "prettier"],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"prettier"
],
"rules": {
"prettier/prettier": "error",
"@typescript-eslint/no-explicit-any": "warn"
}
}
这里要注意,extends 里引入了 prettier,这是为了继承 Prettier 的配置。同时我把 no-explicit-any 设为了 warn 而不是 error,因为现实中完全避免 any 有时候比较难,先让它警告,慢慢优化,不要一上来就把自己逼疯。
再新建一个 .prettierrc 文件来定制格式化风格,比如我用双引号和分号:
{
"semi": true,
"singleQuote": false,
"tabWidth": 2,
"printWidth": 100
}
现在,在 package.json 的 scripts 里加上 lint 和格式化的命令:
{
"scripts": {
"lint": "eslint src --ext .ts",
"format": "prettier --write src/**/*.ts",
"dev": "ts-node src/index.ts",
"build": "tsc",
"start": "node dist/index.js"
}
}
试一下 npm run lint,如果你的代码符合规范,它会静默通过;如果有错,它会红彤彤地列出来。试试 npm run format,你的代码会自动排得整整齐齐,强迫症看了直呼舒适。
第四阶段:测试——确保代码真的靠谱
一个完整的项目不能没有测试。咱们用 jest 来做单元测试,它是目前 JavaScript/TypeScript 生态中最流行的测试框架。
安装依赖:
npm install -D jest ts-jest @types/jest
ts-jest 是让 Jest 能运行 TypeScript 测试文件的关键。
运行初始化命令,自动生成 jest.config.js:
npx ts-jest config:init
这会生成一个配置文件,稍微调整一下,让它指向 src 目录:
/** @type {import('ts-jest').JestConfigWithTsJest} */
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
testMatch: ['**/*.test.ts'],
moduleFileExtensions: ['ts', 'js', 'json'],
};
现在,咱们给刚才的 Repository 写个测试。在 src 目录下新建 repository.test.ts:
import { Repository } from './index';
import { User } from './index';
describe('Repository', () => {
it('should add and retrieve users', () => {
const repo = new Repository<User>();
const user: User = {
id: 1,
name: 'Alice',
age: 25,
email: 'alice@test.com',
role: 'user'
};
repo.add(user);
const users = repo.getAll();
expect(users).toHaveLength(1);
expect(users[0]).toEqual(user);
});
it('should reject invalid user role', () => {
// 这行代码在编译时就会报错,但我们可以用 ts-expect-error 来测试类型约束
// const badUser = { id: 1, name: 'Bob', age: 30, email: 'bob@test.com', role: 'hacker' as any };
// repo.add(badUser);
});
});
在 package.json 里加上测试脚本:
"test": "jest"
执行 npm test,你会看到 Jest 欢快地运行测试并显示绿色通过。如果有 bug,它会详细告诉你哪一行失败了。这就是现代化项目的样子:代码有类型约束,有规范检查,还有自动化测试护航。
第五阶段:打包与部署——走向生产环境
开发完了,代码质量也过关了,怎么发布呢?咱们用刚才配置好的 tsc 把源码编译到 dist 目录。执行 npm run build,你会发现 dist 文件夹里出现了 index.js 和 index.d.ts。
index.js 是给 Node.js 运行的代码,index.d.ts 是给使用你库的其他 TypeScript 项目看的类型定义。
如果这是一个独立的命令行工具或者微服务,你可以直接 npm start 来运行编译后的产物。如果这是一个 npm 包,你需要配置 publishConfig 并确保 package.json 里的 main 指向 dist/index.js,types 指向 dist/index.d.ts:
{
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": [
"dist"
]
}
这样别人 npm install 你的包时,就能拿到编译好的代码和类型定义,享受丝滑的开发体验。
结语:这只是一个开始
好了,朋友。回顾一下,咱们从一个空文件夹开始,安装了 TypeScript 和类型声明,配置了严格的 tsconfig.json,写了带有接口和泛型的代码,引入了 ESLint 和 Prettier 保证代码风格,用 Jest 写了测试,最后编译打包。这一套流程走下来,你拥有的不仅仅是一个项目,而是一套可复用、可扩展、高可靠性的工程化模板。
我知道刚开始学 TypeScript 可能会觉得配置繁琐,类型报错让人头疼,但请相信,这些“麻烦”都是在为你未来的开发速度保驾护航。当你习惯了强类型的约束,当你发现编译器帮你挡住了无数个潜在的崩溃点时,你会回来感谢现在的自己。
记住,技术不是为了炫技,而是为了解决问题。这套配置就是帮你把问题消灭在萌芽状态的利器。现在,打开你的编辑器,创建那个 src/index.ts,让你的第一个 TypeScript 项目跑起来吧!如果有遇到什么奇怪的报错,别慌,Google 一下或者再来问我,咱们一起解决。加油!
