TypeScript 教程(手把手讲解)

什么是 TypeScript?它为何值得学习?

在 JavaScript 的世界里,TypeScript 就像一位细心的“代码质检员”。它在你写代码的时候,就能提前发现潜在的错误,比如把字符串当数字用,或者调用一个不存在的方法。这种“提前发现问题”的能力,让项目在开发阶段就更稳定、更安全。

TypeScript 是 JavaScript 的超集,这意味着所有合法的 JavaScript 代码都是合法的 TypeScript 代码。但 TypeScript 加入了静态类型系统,让你在编译时就能捕捉到类型错误。这就好比你在写作文时,如果系统能自动标出“主语缺失”或“动词时态错误”,写作效率和质量自然会提升。

对于初学者来说,TypeScript 可能会带来一点学习成本,但它的回报非常可观。尤其当你参与团队协作或维护大型项目时,类型系统能极大降低沟通成本,避免因为“我以为这个参数是字符串”而导致的 bug。

如果你正在寻找一份清晰、实用的 TypeScript 教程,那么接下来的内容将带你从零开始,一步步掌握它的核心概念与实际应用。

基础语法:从变量声明开始

TypeScript 的变量声明和 JavaScript 非常相似,但多了一个关键点:类型注解。

let name: string = "Alice";
let age: number = 25;
let isStudent: boolean = true;

这里的 : string: number 就是类型注解。它告诉 TypeScript:“这个变量只能存放字符串、数字或布尔值”。

当你试图赋值一个不匹配的类型时,TypeScript 会报错。比如:

name = 123; // ❌ 错误:不能将 number 赋值给 string 类型

这种“提前拦截错误”的机制,让你在运行代码之前就知道问题所在。就像在开车前检查刹车系统一样,避免了上路后出事故。

变量声明的灵活性

TypeScript 还支持类型推断。如果你在声明变量时就赋值,TypeScript 会自动推断出它的类型,无需手动标注。

let message = "Hello, world!"; // 类型推断为 string
let count = 10; // 类型推断为 number

这既保持了代码简洁,又不失类型安全。你可以把类型推断理解为“聪明的助手”,它能根据你给的值自动判断类型,但你依然可以随时用类型注解来“明确指令”。

函数与类型:让函数更“聪明”

函数是 JavaScript 和 TypeScript 中的核心构建块。TypeScript 通过类型系统,让函数的接口更加清晰。

function add(a: number, b: number): number {
  return a + b;
}

这段代码中:

  • a: numberb: number 是参数类型注解
  • : number 是函数返回值类型
  • 如果你返回一个非数字值,比如 return "123";,TypeScript 会立刻报错

函数的可读性提升

想象一下,你在团队中看到一个函数:

function process(data) {
  return data.map(item => item.toUpperCase());
}

这个函数接受什么类型的 data?返回值是什么?你得手动看逻辑才能猜。而用 TypeScript 写:

function process(strings: string[]): string[] {
  return strings.map(item => item.toUpperCase());
}

现在一眼就能看出:输入是字符串数组,输出也是字符串数组。这种清晰的接口定义,是大型项目中协作的基础。

可选参数与默认值

TypeScript 还支持可选参数和默认值,让函数更灵活:

function greet(name: string, greeting: string = "Hello"): string {
  return `${greeting}, ${name}!`;
}

调用时可以省略 greeting 参数:

greet("Alice"); // 输出:Hello, Alice!
greet("Bob", "Hi"); // 输出:Hi, Bob!

这就像你去餐厅点餐,主菜是必点的,但饮料可以不点(默认是白开水)。

接口与类型别名:定义数据结构的“蓝图”

当你处理复杂的数据时,比如用户信息、商品列表,就需要一种方式来定义这些数据的结构。TypeScript 提供了接口(interface)和类型别名(type alias)来完成这项工作。

使用接口定义对象结构

interface User {
  id: number;
  name: string;
  email: string;
  isActive?: boolean; // 可选属性,用 ? 标记
}

这个 User 接口就像一份“用户信息模板”。任何符合这个结构的对象,都可以被认定为 User 类型。

const user: User = {
  id: 1,
  name: "Alice",
  email: "alice@example.com"
  // isActive 未赋值,但允许,因为是可选属性
};

如果尝试添加一个不存在的属性,比如 phone: "123",TypeScript 会报错,确保数据结构的完整性。

类型别名的灵活性

类型别名可以用来定义更复杂的类型,比如联合类型或元组:

type Status = "pending" | "approved" | "rejected";
type Coordinates = [number, number]; // 元组类型

function move(position: Coordinates): void {
  console.log(`Moving to x: ${position[0]}, y: ${position[1]}`);
}

这里 Status 是一个联合类型,表示只能是三种字符串之一。Coordinates 是一个元组,表示一个包含两个数字的数组。

类型 适用场景 示例
string 文本数据 "Hello"
number 数值计算 42
boolean 逻辑判断 true
Array<T> 列表数据 [1, 2, 3]
object 复杂结构 { name: "A" }

类型别名特别适合在多个地方复用相同的复杂类型,避免重复定义。

类与面向对象编程

TypeScript 完全支持面向对象编程(OOP),并提供了访问修饰符来控制属性和方法的可见性。

class Animal {
  protected name: string; // 只能在类内部或子类访问
  private age: number;    // 只能在当前类内部访问

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }

  public introduce(): string {
    return `Hi, I'm ${this.name}, ${this.age} years old.`;
  }

  protected getAge(): number {
    return this.age;
  }
}

在这个例子中:

  • protected 表示子类可以访问
  • private 表示只有本类能访问
  • public 表示外部可访问

继承与多态

class Dog extends Animal {
  constructor(name: string, age: number) {
    super(name, age);
  }

  public bark(): void {
    console.log("Woof!");
  }

  // 可以重写父类方法
  public introduce(): string {
    return super.introduce() + " I'm a dog!";
  }
}

extends 实现继承,super() 调用父类构造函数。这种机制让代码复用更高效,就像“继承家族基因”一样。

实战:创建一个简单的 Todo 应用

让我们用 TypeScript 写一个简单的待办事项管理器,整合前面学到的知识。

// 定义任务类型
interface Todo {
  id: number;
  text: string;
  completed: boolean;
}

// 任务管理器类
class TodoManager {
  private todos: Todo[] = [];
  private nextId: number = 1;

  // 添加任务
  addTodo(text: string): void {
    const newTodo: Todo = {
      id: this.nextId++,
      text,
      completed: false
    };
    this.todos.push(newTodo);
  }

  // 切换完成状态
  toggleTodo(id: number): void {
    const todo = this.todos.find(t => t.id === id);
    if (todo) {
      todo.completed = !todo.completed;
    }
  }

  // 获取所有任务
  getTodos(): Todo[] {
    return this.todos;
  }
}

// 使用示例
const manager = new TodoManager();
manager.addTodo("学习 TypeScript");
manager.addTodo("写博客文章");

console.log(manager.getTodos());
// 输出:[ { id: 1, text: "学习 TypeScript", completed: false }, ... ]

这个例子展示了:

  • 如何使用接口定义数据结构
  • 如何用类封装逻辑
  • 如何利用类型系统确保数据安全

总结:为什么你应该学 TypeScript?

TypeScript 不只是“加了类型”的 JavaScript,它是一种开发方式的升级。它让你在编写代码时就思考数据结构、函数接口和错误边界。这种“提前思考”的习惯,能显著提升代码质量与团队协作效率。

无论你是初学者还是中级开发者,掌握 TypeScript 都是一项值得投资的技能。它不仅让你写出更健壮的代码,还能在面试中脱颖而出。

如果你正在寻找一份完整、实用的 TypeScript 教程,希望这篇内容能为你打开大门。从今天开始,让类型系统成为你编程路上的“隐形守护者”。