快速过一遍 ts

TypeScript 学习路线图

这是一个从入门到进阶的 TypeScript 语法学习顺序建议。按照这个顺序学习,你的知识体系会更加系统和扎实。


第一阶段:基础核心 (掌握最基本的语法)

1. 基础类型 (Basic Types)

  • 解释: 这是构建所有更复杂类型的基础。
  • 核心类型 : string, number, boolean, null, undefined, symbol, bigint
  • 特殊类型 : any, unknown, void, never
  • 适用场景 :
    • string, number, boolean : 用于明确的原始值类型。这是 TypeScript 最基本的价值,可以防止类型混淆。
      • 示例 : const username: string = "Alice";
    • any (任意类型) : 谨慎使用 。它告诉 TypeScript "放弃类型检查"。
      • 场景: 从旧的 JavaScript 项目逐步迁移时,作为临时方案;或者处理你完全无法预知其结构的第三方库数据。
      • 警告 : any 应该作为最后的选择,过度使用它会使 TypeScript 失去意义。
    • unknown (未知类型) : any 的安全替代品 。它表示"类型未知,在检查之前不准操作"。
      • 场景 : 处理所有外部数据时的最佳实践,如 API 响应、用户输入、文件内容等。它强制你进行类型检查,使代码更安全。
      • 示例 : const response: unknown = JSON.parse(apiData);
    • void : 用于表示一个函数没有任何返回值
      • 示例 : function logMessage(message: string): void { console.log(message); }

2. 数组 (Arrays) 与 元组 (Tuples)

  • 数组 (type[] or Array<type>) :
    • 解释 : 表示一个包含同一种类型元素的列表,长度不限。
    • 场景: 当你需要一个列表,且其中所有元素的类型都相同时。
    • 示例 : 一个商品 ID 列表 const productIds: number[] = [101, 102, 105]; 或文章标签列表 const tags: string[] = ["typescript", "guide"];
  • 元组 ([type1, type2, ...]) :
    • 解释 : 一个固定长度每个位置的类型都已确定的数组。
    • 场景: 当一个数组的不同索引位置代表不同且固定的含义时。
    • 示例 : 表示 HTTP 状态 let httpStatus: [number, string] = [200, "OK"]; 或者 React 的 useState Hook 的返回值 const [count, setCount] = useState(0);

3. 函数 (Functions)

  • 解释 : 为函数的参数返回值提供类型定义。这是 TypeScript 最核心、最强大的功能之一。
  • 场景 : 为你写的每一个函数都添加类型!
    • 确保输入正确 : 防止调用者传入错误类型的数据。 (function greet(name: string))
    • 确保输出可靠 : 让使用者清楚地知道函数会返回什么。 (function calculateTotal(...): number)
    • 提供绝佳的编辑器智能提示,极大地提升开发效率和代码质量。

4. 对象、接口 (Interfaces) 与 类型别名 (Type Aliases)

两者都可以描述对象结构,但有细微差别和侧重点。经验法则是:能用 interface 定义对象结构时就用 interface,其他情况用 type

  • 接口 (interface) :
    • 解释 : 为对象定义一个"契约"或"蓝图"。它可以被类 implements (实现) 和其他接口 extends (继承),更符合面向对象的思想。
    • 场景 : 优先使用 interface 来描述数据结构。比如 API 的响应数据、函数期望接收的对象参数等。
    • 示例 : interface Product { readonly id: number; name: string; price: number; description?: string; }
  • 类型别名 (type) :
    • 解释: 为一个类型创建一个新的名字。它更通用,不仅能描述对象,还能为任何类型(如联合类型、字面量类型)创建别名。
    • 场景 :
      1. 定义联合类型 : 当一个变量可以是多种类型之一时。 type StringOrNumber = string | number;
      2. 定义字面量类型 : 当变量的值只能是一组特定的字符串或数字时。 type Status = "loading" | "success" | "error";
      3. 为复杂的类型命名: 让你免于重复书写冗长的类型定义。

第二阶段:进阶概念 (让你的代码更灵活)

5. 联合类型 (Union Types) 与 交叉类型 (Intersection Types)

  • 联合类型 (|) :
    • 解释: 表示一个值可以是几种类型之一。
    • 场景: 当一个函数参数或变量可能接受不同类型的值时。
    • 示例 : function printId(id: number | string) { ... }
  • 交叉类型 (&) :
    • 解释: 将多个类型合并为一个类型,新类型将拥有所有成员的特性。
    • 场景: 当你需要组合多个已有的类型定义来创建一个更复杂的类型时。
    • 示例 : type AdminUser = User & { permissions: string[]; };

6. 类型断言 (Type Assertions) 与 类型守卫 (Type Guards)

  • 类型断言 (as) :
    • 解释: 当你比 TypeScript 更清楚某个值的类型时,可以"告诉"编译器它的类型。这不会改变运行时的行为,仅仅是在编译时起作用。
    • 场景 : 在处理 unknownany 类型后,你通过自己的逻辑检查确定了其具体类型。
    • 示例 : const name = (response as { name: string }).name;
    • 警告: 不要滥用类型断言,它可能会隐藏真正的类型错误。
  • 类型守卫 :
    • 解释 : 在代码的某个分支中,通过逻辑判断来缩小变量的类型范围。
    • 场景: 在处理联合类型时,需要根据具体类型执行不同逻辑。
    • 示例 : if (typeof id === 'string') { id.toUpperCase(); } (使用 typeof) 或 if (pet instanceof Dog) { pet.bark(); } (使用 instanceof)。

7. 字面量类型 (Literal Types) 与 枚举 (Enums)

  • 字面量类型 :
    • 解释: 将变量的类型限制为某个或某几个具体的字符串或数字。它通常与联合类型一起使用。
    • 场景 : 当函数的参数或变量只能接受几个特定的值时,可以提供比 stringnumber 更精确的类型定义。
    • 示例 : function setAlign(align: "left" | "center" | "right") { ... }
  • 枚举 (enum) :
    • 解释: 用于定义一组命名的常量集合。
    • 场景: 当你有一组相关的常量,并希望给它们赋予一个语义化的名字时。
    • 示例 : enum Direction { Up, Down, Left, Right }。使用 Direction.Up 比使用数字 0 更清晰易懂。

8. 类 (Classes)

  • 解释 : TypeScript 对 ES6 class 的增强,加入了类型注解和访问修饰符。
  • 修饰符 :
    • public: (默认) 任何地方都可以访问。
    • private: 只能在类的内部访问。
    • protected: 只能在类及其子类的内部访问。
    • readonly: 属性只能在声明时或构造函数中被初始化,之后不可修改。
  • 场景 : 在使用面向对象编程(OOP)范式来组织代码时,class 是核心。

第三阶段:高级与泛型 (编写可重用的高质量代码)

9. 泛型 (Generics)

  • 解释 : 泛型是 TypeScript 的一个核心特性,它允许你编写可重用的组件。你可以把它想象成一个类型的"占位符"或"变量",在你使用它时才传入具体的类型。

  • 要解决的问题 : 避免为不同类型重复编写相同的逻辑,同时又不像 any 那样丢失类型信息。

  • 示例:从问题到泛型

    typescript 复制代码
    // 尝试1: 使用 any,丢失了类型信息
    function identityAny(arg: any): any { return arg; }
    const outputAny = identityAny("hello"); // outputAny 的类型是 any
    
    // 解决方案: 使用泛型
    function identity<T>(arg: T): T {
        return arg;
    }
    const output = identity("hello"); // output 的类型被正确推断为 string
  • 核心场景 :

    • 1. 泛型函数 : 创建可重用的、类型安全的函数。

      typescript 复制代码
      // 场景:创建一个函数,它的输入和输出类型可以根据调用时传入的类型动态确定。
      function createSuccessResponse<T>(data: T) {
          return { success: true, data: data };
      }
      const userResponse = createSuccessResponse({ id: 1, name: "Alice" });
      // userResponse.data.id 具有正确的类型提示
    • 2. 泛型接口/类 : 创建可重用的数据结构。

      typescript 复制代码
      // 场景:定义一个分页查询的返回结果,其中列表项的类型是可变的。
      interface PaginatedResult<T> {
          items: T[];
          total: number;
      }
    • 3. 泛型约束 (extends) : 限制泛型 T 必须满足某些条件。

      typescript 复制代码
      // 场景:确保传入的参数一定有 .length 属性。
      function logLength<T extends { length: number }>(arg: T): void {
          console.log(arg.length);
      }
      logLength("hello"); // OK
      // logLength(123); // Error

10. 高级类型 (Advanced Types)

这些类型工具可以让你对已有类型进行变换、组合和提取。

  • keyof (索引类型查询) : 获取一个类型的所有 ,并返回一个由这些键组成的字符串字面量联合类型

    • 场景: 创建能够安全访问对象属性的函数,防止传入不存在的属性名。

    • 示例 :

      typescript 复制代码
      function getProperty<T, K extends keyof T>(obj: T, key: K) {
          return obj[key]; // key 被约束为 obj 中存在的键
      }
  • typeof (类型查询) : 在类型上下文 中,获取一个变量属性 的类型。

    • 场景: 当你想从一个已存在的 JavaScript 对象(如配置对象)中创建类型,而不想手动重复定义时。

    • 示例 :

      typescript 复制代码
      const AppConfig = { apiPrefix: "/api", maxRetries: 3 };
      type Config = typeof AppConfig; // { apiPrefix: string; maxRetries: number; }
  • Mapped Types (映射类型) : 基于一个已有的类型,通过规则转换 它的每一个属性,从而创建一个新类型。

    • 语法 : [P in K]: T,类似 for...in 循环。

    • 场景 : 这是许多内置工具类型(如 Readonly, Partial)的实现基础。

    • 示例 (实现 Readonly) :

      typescript 复制代码
      type MyReadonly<T> = {
          readonly [P in keyof T]: T[P];
      };
  • Conditional Types (条件类型) : 让类型根据一个条件在两种类型中选择一种。

    • 语法 : SomeType extends OtherType ? TrueType : FalseType;

    • infer 关键字 : 在 extends 条件中,可以捕获推断出的类型。

    • 场景: 编写高级工具类型,能从其他类型中"提取"或"解包"出部分类型。

    • 示例 (解包数组元素的类型) :

      typescript 复制代码
      type Flatten<T> = T extends (infer Item)[] ? Item : T;
      type Str = Flatten<string[]>; // 最终类型是 string
      type Num = Flatten<number>;   // 最终类型是 number

11. 工具类型 (Utility Types)

  • 解释: TypeScript 内置了很多方便的、基于泛型和高级类型实现的工具类型,可以直接使用,极大地提高开发效率。
  • 场景/常用示例 :
    • Partial<T>: 将 T 的所有属性变为可选。场景: 更新对象的部分属性时。
    • Readonly<T>: 将 T 的所有属性变为只读。场景: 创建不可变数据。
    • Pick<T, K>: 从 T 中挑选出 K 属性来创建一个新类型。场景: 当你只需要一个大对象中的几个属性时。
    • Omit<T, K>: 从 T 中排除掉 K 属性,用剩下的属性创建新类型。场景 : 与 Pick 相反。
    • ReturnType<T>: 获取函数类型 T 的返回值类型。

第四阶段:工程实践 (将知识应用于真实项目)

12. 模块化 (Modules)

  • 解释 : TypeScript 遵循 ES6 模块标准,使用 importexport 来组织代码结构。
  • 场景: 在任何非 "Hello World" 的项目中,你都应该使用模块化来拆分代码,保持代码的清晰和可维护性。

13. 声明文件 (Declaration Files)

  • 解释 : 后缀为 .d.ts 的文件,它不包含实现,只包含类型定义。
  • 场景 : 当你使用一个纯 JavaScript 编写的库时,它本身没有类型信息。为了在 TypeScript 项目中获得这个库的类型检查和智能提示,你需要为其提供一个声明文件。很多流行的库都有社区维护的 @types/... 包,可以直接安装。

14. tsconfig.json 深度解析

  • 解释: TypeScript 编译器的配置文件,它告诉编译器如何检查和编译你的代码。
  • 场景: 任何 TypeScript 项目的核心。
  • 重要选项 :
    • "target": 编译后输出的 JavaScript 版本。
    • "module": 编译后使用的模块系统。
    • "strict": 开启所有严格类型检查选项,强烈建议始终开启
    • "paths": 设置路径别名,简化模块导入路径。
    • "lib": 指定项目中可以使用的标准库。

学习建议:

  • 扎实走好每一步:不要急于求成,确保理解了前一个概念再进入下一个。
  • 多动手实践:在你的项目中为每个知识点编写一些小例子来加深理解。
  • 保持好奇心:多查阅官方文档,遇到问题积极寻找解决方案。
相关推荐
爷_2 分钟前
Nest.js 最佳实践:异步上下文(Context)实现自动填充
前端·javascript·后端
爱上妖精的尾巴17 分钟前
3-19 WPS JS宏调用工作表函数(JS 宏与工作表函数双剑合壁)学习笔记
服务器·前端·javascript·wps·js宏·jsa
草履虫建模27 分钟前
Web开发全栈流程 - Spring boot +Vue 前后端分离
java·前端·vue.js·spring boot·阿里云·elementui·mybatis
—Qeyser33 分钟前
让 Deepseek 写电器电费计算器(html版本)
前端·javascript·css·html·deepseek
UI设计和前端开发从业者1 小时前
从UI前端到数字孪生:构建数据驱动的智能生态系统
前端·ui
Junerver2 小时前
Kotlin 2.1.0的新改进带来哪些改变
前端·kotlin
千百元3 小时前
jenkins打包问题jar问题
前端
喝拿铁写前端3 小时前
前端批量校验还能这么写?函数式校验器组合太香了!
前端·javascript·架构
巴巴_羊3 小时前
6-16阿里前端面试记录
前端·面试·职场和发展
我是若尘3 小时前
前端遇到接口批量异常导致 Toast 弹窗轰炸该如何处理?
前端