万字血书!TypeScript 完全指南

TypeScript 完全指南(大纲)

第1章:TypeScript 简介

1.1 什么是 TypeScript?

TypeScript 是微软开发的开源编程语言,它是 JavaScript 的超集 (Superset),意味着所有合法的 JavaScript 代码都可以直接在 TypeScript 中运行。TypeScript 的核心特性是静态类型检查 ------开发者可以在编码阶段为变量、函数参数、返回值等标注类型,编译器(tsc)会在代码运行前检查类型错误,从而提前发现潜在问题。例如:

typescript 复制代码
function add(a: number, b: number): number {
  return a + b;
}
// 调用时传入非数字会触发编译错误:add("1", 2);

1.2 为什么选择 TypeScript?

  • 类型安全 :减少运行时错误(如 undefined is not a function)。
  • 开发体验:IDE 智能提示、自动补全和重构支持(如 VS Code)。
  • 渐进式:支持逐步迁移,可在现有 JavaScript 项目中局部引入。
  • 生态兼容:编译后的代码是纯 JavaScript,兼容所有浏览器和 Node.js。

1.3 快速上手

  1. 安装环境

    bash 复制代码
    npm install -g typescript  # 全局安装 TypeScript 编译器
    tsc --version             # 验证安装
  2. 编写第一个程序

    创建 hello.ts

    typescript 复制代码
    let message: string = "Hello, TypeScript!";
    console.log(message);
  3. 编译与运行

    bash 复制代码
    tsc hello.ts    # 生成 hello.js
    node hello.js   # 输出结果

1.4 TypeScript 的定位

TypeScript 并非替代 JavaScript,而是通过类型系统增强其工程化能力,尤其适合大型项目或团队协作。下一章将深入讲解基础类型与语法。


第2章:基础类型与语法

TypeScript 的基础类型系统通过显式注解增强了代码的可读性和安全性。合理使用这些类型可以大幅减少运行时错误,提升开发效率。

2.1 原始类型(Primitive Types)

TypeScript 的原始类型与 JavaScript 一致,但需要通过类型注解显式声明。

1. string

  • 表示文本数据,可用单引号、双引号或反引号(模板字符串)。

  • 严格类型检查:无法赋值非字符串值。

    typescript 复制代码
    let name: string = "Alice";
    let greeting: string = `Hello, ${name}!`; // 模板字符串
    // name = 100; // 错误:不能将 number 赋值给 string

2. number

  • 包括整数、浮点数、二进制、八进制、十六进制等所有数值类型。

  • 没有独立的 intfloat ,统一用 number

    typescript 复制代码
    let decimal: number = 6;
    let hex: number = 0xf00d;     // 十六进制
    let binary: number = 0b1010;  // 二进制
    let infinity: number = Infinity;

3. boolean

  • 仅允许 truefalse

  • 禁止隐式转换 :不能直接用 0"" 等表示假值。

    typescript 复制代码
    let isDone: boolean = false;
    // isDone = ""; // 错误:不能将 string 赋值给 boolean

2.2 数组与元组

1. 数组(Array)

  • 语法类型[]Array<类型>

  • 所有元素必须为同一类型。

    typescript 复制代码
    let numbers: number[] = [1, 2, 3];
    let names: Array<string> = ["Alice", "Bob"];
    // numbers.push("4"); // 错误:类型不匹配

2. 元组(Tuple)

  • 固定长度和类型的数组,适合存储结构化数据。

  • 越界检查:超出定义长度会报错。

    typescript 复制代码
    let user: [string, number] = ["Alice", 30];
    // user = ["Bob", 40, true]; // 错误:长度超过 2
  • 可选元素与剩余元素(TypeScript 4.0+):

    typescript 复制代码
    let option: [string, number?] = ["Alice"];       // 第二个元素可选
    let list: [string, ...number[]] = ["Alice", 1, 2]; // 剩余元素为 number 数组

2.3 枚举(Enum)

  • 用于定义命名常量集合,支持数字或字符串值。

1. 数字枚举

  • 默认从 0 开始自增,可手动赋值。

    typescript 复制代码
    enum Direction { 
      Up = 1,   // 显式赋值
      Down,     // 自动递增为 2
      Left = 10,
      Right     // 自动递增为 11
    }
    console.log(Direction.Up); // 输出: 1

2. 字符串枚举

  • 必须为每个成员显式赋值字符串。

    typescript 复制代码
    enum LogLevel {
      Error = "ERROR",
      Warn = "WARN"
    }

3. 常量枚举(Const Enum)

  • 编译时会被删除,直接替换为常量值,减少代码体积。

    typescript 复制代码
    const enum Size { Small = 10, Medium, Large }
    let size = Size.Medium; // 编译后:let size = 11;

2.4 anyunknownvoidnever

1. any

  • 关闭类型检查:可赋值任意类型,慎用(破坏类型安全)。

    typescript 复制代码
    let data: any = "Hello";
    data = 100;       // 合法
    data.toFixed();   // 编译通过,但运行时可能报错!

2. unknown

  • 类型安全的 any:必须通过类型断言或收窄后使用。

    typescript 复制代码
    let input: unknown = fetchUserInput();
    // let name: string = input; // 错误:unknown 不能直接赋值
    if (typeof input === "string") {
      let name: string = input; // 类型收窄后合法
    }

3. void

  • 表示函数没有返回值

    typescript 复制代码
    function logMessage(msg: string): void {
      console.log(msg);
      // 无 return 语句
    }

4. never

  • 表示函数永远不会返回(如抛出错误或无限循环)。

    typescript 复制代码
    function error(message: string): never {
      throw new Error(message);
    }
    function infiniteLoop(): never {
      while (true) {}
    }

第3章:类型进阶

TypeScript 的类型系统不仅限于基础类型,还提供了强大的工具来描述复杂的数据结构和逻辑。本章将深入讲解接口(Interface)联合类型(Union Types)类型别名(Type Alias)类型断言(Type Assertion)类型守卫(Type Guard) 等高级类型用法。


3.1 接口(Interface)

接口用于定义对象的形状(属性和方法),是 TypeScript 的核心类型工具。

1. 基本用法

typescript 复制代码
interface User {
  name: string;
  age: number;
}

const alice: User = {
  name: "Alice",
  age: 30,
  // isAdmin: true  // 错误:接口未定义 isAdmin
};

2. 可选属性与只读属性

  • 可选属性 :通过 ? 标记。
  • 只读属性 :通过 readonly 标记,初始化后不可修改。
typescript 复制代码
interface Config {
  readonly id: string;  // 只读
  title: string;
  maxRetries?: number;  // 可选
}

const config: Config = {
  id: "123",
  title: "API Config",
};
// config.id = "456";  // 错误:只读属性不可修改

3. 函数类型

接口可以描述函数结构:

typescript 复制代码
interface SearchFunc {
  (source: string, keyword: string): boolean;
}

const search: SearchFunc = (src, kw) => src.includes(kw);

4. 接口继承

通过 extends 实现接口复用:

typescript 复制代码
interface Animal {
  name: string;
}

interface Dog extends Animal {
  bark(): void;
}

const myDog: Dog = {
  name: "Buddy",
  bark: () => console.log("Woof!"),
};

5. 索引签名

描述动态属性名的类型,常用于字典结构:

typescript 复制代码
interface StringArray {
  [index: number]: string;  // 索引为数字,值为字符串
}

const arr: StringArray = ["Alice", "Bob"];
console.log(arr[0]); // 输出: "Alice"

3.2 联合类型与类型别名

1. 联合类型(Union Types)

允许变量为多种类型之一:

typescript 复制代码
type ID = string | number;

function printId(id: ID) {
  console.log(id);
}

printId("ABC123");  // 合法
printId(100);       // 合法

2. 类型别名(Type Alias)

为复杂类型定义简洁的名称:

typescript 复制代码
type Point = {
  x: number;
  y: number;
};

type Callback = (data: string) => void;

3. 联合类型与字面量

结合字面量类型限制取值范围:

typescript 复制代码
type Status = "success" | "error" | "pending";
type Dice = 1 | 2 | 3 | 4 | 5 | 6;

let currentStatus: Status = "success";
let roll: Dice = 4;

3.3 类型断言

手动指定值的类型,适用于开发者比编译器更清楚类型的情况。

1. as 语法

typescript 复制代码
const input = document.getElementById("input") as HTMLInputElement;
input.value = "Hello";  // 断言后可以安全访问 value 属性

2. 非空断言(!

明确告诉编译器值不为 null/undefined

typescript 复制代码
function getLength(str?: string) {
  return str!.length;  // 慎用:需确保 str 不为空
}

3.4 类型守卫

通过逻辑判断缩小变量类型范围。

1. typeof 守卫

typescript 复制代码
function printValue(value: string | number) {
  if (typeof value === "string") {
    console.log(value.toUpperCase());
  } else {
    console.log(value.toFixed(2));
  }
}

2. instanceof 守卫

typescript 复制代码
class Cat { meow() {} }
class Dog { bark() {} }

function handlePet(pet: Cat | Dog) {
  if (pet instanceof Cat) {
    pet.meow();
  } else {
    pet.bark();
  }
}

3. 自定义类型守卫

通过返回值为 value is Type 的函数定义逻辑:

typescript 复制代码
interface Fish { swim(): void }
interface Bird { fly(): void }

function isFish(pet: Fish | Bird): pet is Fish {
  return (pet as Fish).swim !== undefined;
}

function move(pet: Fish | Bird) {
  if (isFish(pet)) {
    pet.swim();
  } else {
    pet.fly();
  }
}

3.5 类型兼容性

TypeScript 使用结构化类型系统(Duck Typing),只要结构匹配即可兼容。

1. 对象兼容性

typescript 复制代码
interface Named { name: string }
let x: Named;
const y = { name: "Alice", age: 30 };
x = y;  // 合法:y 包含 name 属性

2. 函数兼容性

参数类型和返回值类型需兼容:

typescript 复制代码
type Handler = (a: number) => void;

const handler1: Handler = (a: number) => {};
const handler2: Handler = (a: number, b: string) => {};  // 错误:参数数量不兼容

第4章:函数与类

TypeScript 在函数和类的定义中引入了严格的类型系统,使得面向对象编程更加安全和可维护。本章将详细讲解函数类型、类的基本语法、继承机制、访问修饰符等核心内容,并深入探讨抽象类与接口的应用。


4.1 函数类型

1. 函数参数与返回值的类型注解

  • 参数类型:显式声明参数类型。

  • 返回值类型:可显式标注返回值类型,编译器会自动推断。

    typescript 复制代码
    function add(a: number, b: number): number {
      return a + b;
    }
    // 箭头函数类型
    const multiply = (x: number, y: number): number => x * y;

2. 可选参数与默认参数

  • 可选参数 :通过 ? 标记,必须位于必选参数之后。

  • 默认参数:直接赋值默认值,类型可自动推断。

    typescript 复制代码
    function greet(name: string, greeting: string = "Hello", suffix?: string): string {
      return `${greeting}, ${name}${suffix ? " " + suffix : ""}!`;
    }
    greet("Alice"); // 输出: "Hello, Alice!"
    greet("Bob", "Hi", "Mr."); // 输出: "Hi, Bob Mr.!"

3. 剩余参数(Rest Parameters)

  • 将多个参数收集为数组,类型必须为数组。

    typescript 复制代码
    function sum(...numbers: number[]): number {
      return numbers.reduce((acc, curr) => acc + curr, 0);
    }
    sum(1, 2, 3); // 输出: 6

4. 函数重载(Function Overloads)

  • 为同一函数提供多个类型定义,解决多态场景的类型问题。

    typescript 复制代码
    // 重载签名
    function formatInput(input: string): string;
    function formatInput(input: number): string;
    
    // 实现签名(需兼容所有重载)
    function formatInput(input: string | number): string {
      return typeof input === "string" ? input.trim() : input.toFixed(2);
    }
    
    formatInput("  text  "); // 返回 "text"
    formatInput(3.1415);     // 返回 "3.14"

4.2 类的类型化

1. 类的基本语法

  • 属性类型 :必须在类中显式声明类型(除非通过构造函数赋值且启用 strictPropertyInitialization)。

  • 构造函数 :使用 constructor 定义。

    typescript 复制代码
    class Person {
      name: string;
      age: number;
    
      constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
      }
    
      sayHello(): string {
        return `Hello, I'm ${this.name}`;
      }
    }
    
    const alice = new Person("Alice", 30);

2. 访问修饰符(Access Modifiers)

  • public:默认修饰符,可在任何地方访问。

  • private:仅类内部访问。

  • protected:类内部和子类中访问。

    typescript 复制代码
    class Animal {
      public name: string;
      private secret: string = "hidden";
      protected age: number;
    
      constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
      }
    }
    
    class Dog extends Animal {
      bark() {
        console.log(this.age);  // 合法:protected 属性

第5章:泛型(Generics)

泛型是 TypeScript 中用于编写可复用、灵活且类型安全的代码的核心工具。它允许开发者定义函数、类或接口时不预先指定具体类型,而是在使用时动态指定类型,从而避免重复代码并保持类型约束。本章将深入讲解泛型的使用场景、语法和高级技巧。


5.1 泛型的基本概念

1. 为什么需要泛型?

假设需要编写一个函数,返回传入的任意类型的参数:

typescript 复制代码
// 无泛型:使用 any 会丢失类型信息
function identity(arg: any): any {
  return arg;
}
const num = identity(100); // num 的类型为 any,无法推断为 number

使用泛型可以保留类型信息:

typescript 复制代码
function identity<T>(arg: T): T {
  return arg;
}
const num = identity<number>(100); // num 类型为 number
const str = identity("Hello");     // 类型自动推断为 string

2. 泛型语法

  • 类型参数 :使用 <T> 定义泛型参数(T 是约定俗成的名称,可自定义)。
  • 动态绑定:调用时显式指定类型或由编译器自动推断。

5.2 泛型函数

1. 基本用法

typescript 复制代码
function logAndReturn<T>(value: T): T {
  console.log(value);
  return value;
}

logAndReturn<string>("Hello"); // 显式指定类型
logAndReturn(42);              // 自动推断为 number

2. 多类型参数

可定义多个泛型参数,用逗号分隔:

typescript 复制代码
function swap<T, U>(tuple: [T, U]): [U, T] {
  return [tuple[1], tuple[0]];
}

const result = swap(["Alice", 30]); // 类型推断为 [number, string]

5.3 泛型接口

1. 接口中的泛型

定义可复用的通用结构:

typescript 复制代码
interface KeyValuePair<K, V> {
  key: K;
  value: V;
}

const pair1: KeyValuePair<string, number> = { key: "age", value: 30 };
const pair2: KeyValuePair<number, boolean> = { key: 1, value: true };

2. 函数类型泛型

描述通用函数结构:

typescript 复制代码
interface GenericFunc<T> {
  (arg: T): T;
}

const numericFunc: GenericFunc<number> = (x) => x * 2;
numericFunc(10); // 返回 20

5.4 泛型类

1. 类中的泛型

用于创建可处理多种类型的容器类:

typescript 复制代码
class Box<T> {
  private content: T;

  constructor(value: T) {
    this.content = value;
  }

  getValue(): T {
    return this.content;
  }
}

const numberBox = new Box<number>(100);
const stringBox = new Box("Hello"); // 自动推断为 Box<string>

2. 泛型约束

限制泛型参数的类型范围,使用 extends 关键字:

typescript 复制代码
interface HasLength {
  length: number;
}

function logLength<T extends HasLength>(arg: T): void {
  console.log(arg.length);
}

logLength("Hello"); // 合法,string 有 length 属性
logLength([1, 2, 3]); // 合法,数组有 length
// logLength(100);    // 错误:number 没有 length

3. keyof 约束

确保访问对象属性的安全性:

typescript 复制代码
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

const user = { name: "Alice", age: 30 };
getProperty(user, "name"); // 返回 "Alice"
// getProperty(user, "email"); // 错误:email 不是 user 的属性

5.5 泛型工具类型

TypeScript 内置了一些泛型工具类型,简化常见类型操作。

1. Partial<T>

将类型 T 的所有属性变为可选:

typescript 复制代码
interface User {
  name: string;
  age: number;
}

type PartialUser = Partial<User>;
// 等效于 { name?: string; age?: number; }

2. Readonly<T>

将类型 T 的所有属性变为只读:

typescript 复制代码
type ReadonlyUser = Readonly<User>;
// 等效于 { readonly name: string; readonly age: number; }

3. Pick<T, K>

从类型 T 中选择部分属性 K

typescript 复制代码
type UserName = Pick<User, "name">; // { name: string }

4. Record<K, T>

定义键为 K、值为 T 的对象类型:

typescript 复制代码
type UserMap = Record<string, User>;
// 等效于 { [key: string]: User }

5.6 泛型默认类型

为泛型参数提供默认值,简化调用时的类型声明:

typescript 复制代码
interface ResponseData<T = string> {
  code: number;
  data: T;
}

const stringResponse: ResponseData = { code: 200, data: "OK" }; // T 默认为 string
const numberResponse: ResponseData<number> = { code: 200, data: 100 };

5.7 泛型的实际应用

1. API 响应类型

定义通用的 API 响应结构:

typescript 复制代码
interface ApiResponse<T> {
  success: boolean;
  data: T;
  error?: string;
}

// 用户数据接口
interface UserData { id: string; name: string }

// 具体调用
const userResponse: ApiResponse<UserData> = await fetchUser();

2. React 组件 Props

在 React 中定义泛型组件:

typescript 复制代码
interface ListProps<T> {
  items: T[];
  renderItem: (item: T) => React.ReactNode;
}

function List<T>({ items, renderItem }: ListProps<T>) {
  return <div>{items.map(renderItem)}</div>;
}

// 使用示例
<List<number> items={[1, 2, 3]} renderItem={(n) => <div>{n}</div>} />;

第6章:模块与命名空间

模块(Module)和命名空间(Namespace)是 TypeScript 中管理代码作用域、组织复杂项目的核心机制。它们帮助开发者避免全局命名冲突,实现代码的模块化和复用。本章将深入探讨模块的导入导出、命名空间的设计模式,以及如何结合现代工具构建可维护的代码结构。


6.1 模块(Modules)

1. 模块的基本概念

  • 模块化编程 :将代码拆分为独立的文件,每个文件是一个模块,通过 import/export 管理依赖。
  • 作用域隔离:模块内的变量、函数、类默认在模块作用域内,不污染全局。

2. ES Module 语法

  • 导出(Export)

    typescript 复制代码
    // math.ts
    export const PI = 3.14;                  // 导出常量
    export function sum(a: number, b: number): number {  // 导出函数
      return a + b;
    }
    export class Calculator {                // 导出类
      static multiply(a: number, b: number): number {
        return a * b;
      }
    }
    
    // 默认导出(每个模块仅一个)
    export default class AdvancedCalculator extends Calculator {}
  • 导入(Import)

    typescript 复制代码
    // app.ts
    import { PI, sum } from "./math";        // 命名导入
    import AdvancedCalculator from "./math"; // 默认导入
    import * as MathUtils from "./math";     // 全部导入为命名空间
    
    console.log(PI);                         // 3.14
    console.log(sum(2, 3));                  // 5
    const calc = new AdvancedCalculator();

3. 模块编译与配置

  • 模块类型 :在 tsconfig.json 中指定模块系统(如 "module": "ES2020""CommonJS")。
  • 文件扩展名 :TypeScript 支持 .ts.tsx.mts(ES 模块)和 .cts(CommonJS 模块)。

6.2 命名空间(Namespaces)

1. 命名空间的作用

  • 逻辑分组:将相关功能组织在单一命名空间内,避免全局污染。
  • 兼容性:适用于旧代码或浏览器环境(现代项目推荐使用模块)。

2. 定义与使用

typescript 复制代码
// utilities.ts
namespace Utilities {
  export function log(msg: string): void {  // 导出才能在外部访问
    console.log(msg);
  }

  export namespace MathHelper {             // 嵌套命名空间
    export const PI = 3.14;
  }
}

// 使用命名空间
Utilities.log("Hello");                     // 输出: Hello
console.log(Utilities.MathHelper.PI);       // 输出: 3.14

3. 多文件命名空间

通过 /// <reference path="..." /> 合并多个文件的命名空间:

  • file1.ts

    typescript 复制代码
    namespace Utilities {
      export function log(msg: string) { ... }
    }
  • file2.ts

    typescript 复制代码
    /// <reference path="file1.ts" />
    namespace Utilities {
      export function debug(msg: string) { ... }
    }
  • 编译后 :两个文件的 Utilities 命名空间会被合并。


6.3 模块与命名空间的对比

特性 模块 命名空间
作用域 文件作用域 全局或命名空间作用域
依赖管理 显式 import/export 隐式通过命名空间引用
适用场景 现代浏览器/Node.js 项目 旧项目或浏览器环境
编译输出 根据配置生成 ES/CommonJS 模块 合并为全局对象或 IIFE
推荐使用 ✅ 优先选择模块 ⚠️ 仅在必要时使用

6.4 模块解析策略

1. 解析方式

  • 相对路径import "./math" 解析为当前目录下的文件。
  • 非相对路径import "lodash"node_modules 或配置的路径解析。

2. 路径别名配置

tsconfig.json 中配置 paths 简化导入路径:

json 复制代码
{
  "compilerOptions": {
    "baseUrl": "./src",
    "paths": {
      "@utils/*": ["utils/*"]  // 将 @utils/ 映射到 src/utils/
    }
  }
}

使用示例:

typescript 复制代码
import { log } from "@utils/logger";  // 实际路径: src/utils/logger.ts

6.5 声明文件(.d.ts)

1. 声明文件的作用

为第三方 JavaScript 库或全局变量提供类型定义,增强 TypeScript 支持。

2. 声明全局模块

typescript 复制代码
// global.d.ts
declare module "jquery" {
  export function $(selector: string): any;
  export namespace $ {
    function ajax(url: string): void;
  }
}

3. 声明全局变量

typescript 复制代码
declare const VERSION: string;  // 声明全局常量
declare interface Window {
  MY_APP_CONFIG: Record<string, any>;  // 扩展全局 Window 类型
}

6.6 模块的进阶用法

1. 动态导入(Dynamic Import)

按需加载模块,返回 Promise:

typescript 复制代码
async function loadModule() {
  const math = await import("./math");
  console.log(math.sum(1, 2));
}

2. 重新导出(Re-export)

聚合多个模块的导出:

typescript 复制代码
// utils/index.ts
export { log } from "./logger";
export { encrypt } from "./crypto";

3. 模块的副作用

执行模块代码但不导入任何内容:

typescript 复制代码
import "./polyfills";  // 执行 polyfills.ts 中的初始化代码

相关推荐
狂炫一碗大米饭35 分钟前
🧠前端面试高频考题---promise,从五个方面搞定它🛠️
前端·javascript·面试
拉不动的猪1 小时前
前端如何判断登录设备是移动端还是pc端
前端·javascript·css
小圆脸儿1 小时前
通用组件库设计方案ui-components
前端·前端框架
拉不动的猪1 小时前
刷刷题38(长连接 +切片上传)
前端·javascript·面试
哀木1 小时前
随笔之 react 接入 @xterm 的踩坑记录
前端
野生的程序媛1 小时前
重生之我在学Vue--第13天 Vue 3 单元测试实战指南
前端·javascript·vue.js·单元测试
Aphasia3112 小时前
简单介绍清除浮动解决高度塌陷的四种方法✍🏻
前端·css
二川bro2 小时前
TypeScript接口 interface 高级用法完全解析
javascript·typescript
Captaincc2 小时前
这款堪称编程界的“自动驾驶”利器,集开发、调试、提 PR、联调、部署于一体
前端·ai 编程