- 转译 (Transpilation):浏览器和 Node.js 只能直接运行 JavaScript。因此,TS 代码必须通过其编译器(tsc)被“转译”成纯粹的 JavaScript 代码才能运行。
- 记住: TS 引入的所有类型注解(如 : string)在转译后的 JS 代码中都会被擦除。类型系统只在开发和编译阶段起作用,不影响运行时行为。
| 特性 | 描述 | 实际价值(对你的助益) |
|---|---|---|
| 类型系统 (Type System) | 支持基础类型、接口 (interface)、联合类型 (Union Type)、泛型 (Generics) 等复杂结构。 | 代码即文档。 你不需要查看函数实现,仅看其类型定义就能知道它接受什么、返回什么。 |
| 工具支持 (Tooling) | 基于类型信息,现代 IDE(如 VS Code)能提供强大的功能。 | 开发效率大幅提升。 智能代码补全、快速导航到定义、重构更容易、错误提示更准确。 |
| 面向对象 (OOP) | 完整支持类 (Class)、接口 (Interface)、抽象类等,比原生 JS 的 OOP 更清晰。 | 适用于大型、复杂的应用。 强制结构化和模块化,提高代码的可维护性和可协作性。 |
| ESNext 支持 | 允许你使用最新的 JavaScript 语法特性(如 ES Modules, async/await 等),并能将它们转译成兼容旧环境的 JS。 | 保持技术栈现代化,同时确保代码在各种目标环境下运行。 |
- 接受摩擦,视为投资: 每次你被 TS 编译器抱怨缺少类型时,不要绕过它,而要将其视为一次投资。这迫使你明确思考数据的结构 (Shape) 和预期用途。你花一分钟定义类型,可以节省未来十小时的调试。
- 从接口 (Interface) 开始: 不要纠结于复杂的类型技巧。先从定义你应用中的核心数据结构开始(Interfaces)。它们是应用状态和数据流的蓝图。
- 拥抱渐进式类型 (Gradual Typing): 如果是旧项目,不要妄想一次性全部转换。从测试代码、新的核心模块,或关键的 API 接口开始引入 TS。使用 any 作为临时逃生口,但将其视为代码债务,并在下次重构时移除。
// JS: 结构是隐式的。你不知道 profile 应该包含什么。function printUserProfile(userProfile) { // 如果 userProfile.age 不存在,或不是数字,运行时就会出错 console.log(`User: $, Age: $`);}const dataFromApi = { neme: "Alice", // 拼写错误,运行时静默失败 age: "25岁" // 错误类型,运行时静默失败};printUserProfile(dataFromApi);
// 1. 定义接口 (Interface) - 明确的数据蓝图interface UserProfile { name: string; // 必须是字符串 age: number; // 必须是数字 isVerified?: boolean; // 可选属性,可能存在或不存在}// 2. 强制参数遵循接口function printUserProfile(userProfile: UserProfile): void { // TS 确保 userProfile.name 和 userProfile.age 一定存在且类型正确 console.log(`User: $, Age: $`);}// 3. 编译器立刻发现错误!const dataFromApi: UserProfile = { neme: "Alice", // 错误:属性 'neme' 不存在于类型 'UserProfile' 中。 age: "25岁" // 错误:不能将类型 'string' 分配给类型 'number'。};// 4. 正确的调用const validData: UserProfile = { name: "Bob", age: 30, isVerified: true};printUserProfile(validData);
/** * 接受一个字符串或一个数字作为输入。 * 总是返回一个字符串或一个数字。 */function processInput(input: string | number): string | number { // 编译器要求你在使用特定类型方法前进行类型收窄 (Narrowing) if (typeof input === 'string') { return input.toUpperCase(); // 此时 input 被收窄为 string } // 否则 input 此时确定为 number return input * 2;}// 1. 调用时得到 IDE 提示const result1 = processInput("hello"); // 鼠标悬停在 result1 上:类型是 string | number// 2. 传递错误类型时,编译器立刻报错processInput(true); // 错误:类型 'boolean' 不可分配给类型 'string | number'。
/** * 泛型函数:接受任何类型 T,并返回相同类型 T 的值。 * T 只是一个占位符名称。 */function identityT>(arg: T): T { // 保持输入和输出的类型一致 return arg;}// 1. 明确指定类型 (可选)const strOutput = identitystring>("hello world"); // strOutput 的类型被确定为 string// 2. 编译器自动推断类型 (更常见)const numOutput = identity(42); // 编译器推断 T 为 number,numOutput 的类型被确定为 number// 3. 后续操作的类型安全保障numOutput.toFixed(2); // ✅ 正确,因为它是 number// strOutput.toFixed(2); // ❌ 错误:属性 'toFixed' 不存在于类型 'string' 上。