TypeScript 泛型与类型系统:从入门到精通

TypeScript 泛型与类型系统:从入门到精通

TypeScript 作为 JavaScript 的类型超集,为我们提供了强大的类型系统。今天,就让我们一起探索 TS 中的泛型、type 和 interface,解锁类型安全的新姿势!🚀

前言:为什么需要 TypeScript?

JavaScript 作为一门弱类型语言,开发时非常灵活,但这种灵活性也带来了很多问题:

javascript 复制代码
// JavaScript 弱类型,容易出问题
let num = 1;
num = 'hello'; // 这在 JS 中是合法的,但可能导致后续代码出错
num.toFixed(2); // 运行时才会报错:Uncaught TypeError

TypeScript 的出现正是为了解决这些问题!它为我们带来了类型的约束,让错误在编译阶段就能被发现。

有趣的是,TypeScript 的诞生还有一个背景:微软想让 Java 工程师更容易地编写前端代码。如今,React + TypeScript 已经成为前端开发的标配,掌握 TS 是每个前端开发者的必备技能!

ts与js对比

特性 JavaScript TypeScript
类型检查 运行时(动态) 编译时(静态)✅
错误发现 运行时才暴露 编写时即可发现✅
IDE 智能提示 基础 强大、精准✅
代码可读性 依赖注释和命名 类型即文档✅
大型项目维护 易出错、难重构 更安全、易维护✅
学习成本 稍高(需学类型系统)
构建步骤 需编译(tsc)

第一部分:泛型 - 类型的函数

1.1 什么是泛型?

泛型是类型的函数,T 是它的占位符,接受类型参数并返回新类型。泛型在类型层面引入了参数化机制,核心目标是在编译期间提供类型安全,同时保持代码的复用性。

1.2 解决 any 滥用问题

很多 TS 新手会滥用 any 类型:

typescript 复制代码
let a: any = 1; // any 表示可以是任何类型
a = '12'; // 不能滥用any,这失去了TS的意义

function getFirstElement(arr: any[]): any {
  return arr[0];
}

const numbers = [1, 2, 3, 4];
const firstNum = getFirstElement(numbers);
console.log(firstNum); // any类型
firstNum.toFixed(2); // 运行时可能报错!

const strs = ['1', '2', '3'];
const firstStr = getFirstElement(strs);
console.log(firstStr); // any类型

这种情况下,我们失去了 TypeScript 的类型检查优势。泛型正是解决这个问题的利器!

1.3 泛型的基本使用

typescript 复制代码
// 使用泛型来提高函数的复用性
function getFirstElement2<T>(arr: T[]): T | undefined {
  return arr.length ? arr[0] : undefined;
}

// 显式指定类型参数
const firstNum2 = getFirstElement2<number>(numbers);
firstNum2?.toFixed(2); // 安全的使用方式
console.log(firstNum2); // number类型

// TypeScript 类型推导,自动推断类型
const firstStr2 = getFirstElement2(strs);
console.log(firstStr2); // string类型
  1. 定义泛型

    使用 <T>(T 是约定俗成的名称,也可用其他字母)来声明一个类型变量,代表"某种未知类型"。

    ts 复制代码
    function identity<T>(arg: T): T {
      return arg;
    }
  2. 调用泛型函数

    • 自动推导:TypeScript 会根据传入的值自动推断类型。

      ts 复制代码
      const result = identity("hello"); // T 被推断为 string
    • 手动指定:你也可以显式指定类型。

      ts 复制代码
      const result = identity<number>(42); // T 是 number
  3. 应用于数组、对象等 常用于处理多种类型的数组或结构,保持类型安全。

    ts 复制代码
    function getFirst<T>(arr: T[]): T | undefined {
      return arr[0];
    }
    
    getFirst([1, 2, 3]);     // 返回 number | undefined
    getFirst(["a", "b"]);    // 返回 string | undefined

1.4 实践:用泛型实现链表

让我们用一个更复杂的例子来加深理解 - 实现一个支持泛型的链表数据结构:

typescript 复制代码
// 用泛型去声明一个链表
// 支持泛型的节点,可以接受value类型的传参
class NodeItem<T> {
  value: T;
  next: NodeItem<T> | null = null;
  
  constructor(value: T) {
    this.value = value;
  }
}

class LinkedList<T> {
  head: NodeItem<T> | null = null;
  
  append(value: T): void {
    const newNodeItem = new NodeItem(value);
    
    if (!this.head) {
      this.head = newNodeItem;
      return;
    }
    
    let current = this.head;
    while (current.next) {
      current = current.next;
    }
    
    current.next = newNodeItem;
  }
}

// 使用泛型链表存储数字
const numberList = new LinkedList<number>();
numberList.append(1);
numberList.append(2);
numberList.append(3);
console.log(numberList);

// 使用泛型链表存储自定义类型
interface User {
  id: number;
  name: string;
}

const userList = new LinkedList<User>();
userList.append({
  id: 1,
  name: '张三',
});

这个例子展示了泛型的强大之处:我们可以创建可重用的数据结构,同时保持完整的类型安全!

第二部分:type 与 interface - 类型的艺术

在 TypeScript 中,我们有两种主要方式来定义自定义类型:typeinterface。它们看似相似,实则各有特点。

2.1 基本概念与使用

interface(接口)
  • 作用:定义对象的形状(有哪些属性、方法及其类型)。

  • 语法

    ts 复制代码
    interface Person {
      name: string;
      age: number;
    }
  • 使用

    ts 复制代码
    const user: Person = { name: '张三', age: 25 };

特点:支持扩展 (继承)和合并(同名接口自动合并)。


type(类型别名)
  • 作用:给一个类型起个别名,可以是对象、联合类型、原始类型等。

  • 语法

    ts 复制代码
    type Person = {
      name: string;
      age: number;
    }
  • 使用

    ts 复制代码
    const user: Person = { name: '李四', age: 30 };

特点:更灵活,可定义联合类型元组等复杂类型。

typescript 复制代码
// interface 关键字
interface UserDemo {
  name: string;
  age: number;
}

// type 关键字
type UserType = {
  name: string;
  age: number;
}

// 使用方式相同
const u1: UserDemo = { name: '张三', age: 18 };
const u2: UserType = { name: '李四', age: 19 };

2.2 相同点:都能描述对象和函数

都可以描述一个对象或者函数:

typescript 复制代码
// 描述函数类型
interface AddFn {
  (a: number, b: number): number;
}

type AddType = (a: number, b: number) => number;

// 描述对象类型
interface Person {
  name: string;
  age: number;
}

type PersonType = {
  name: string;
  age: number;
};

都允许扩展:

typescript 复制代码
// interface 扩展
interface Person {
  name: string;
}

interface Employee extends Person {
  job: string;
}

// type 扩展
type PersonType = {
  name: string;
};

type EmployeeType = PersonType & {
  job: string;
};

2.3 不同点:各有所长

1. 继承方式不同
typescript 复制代码
// interface 使用 extends
interface Animal {
  name: string;
}

interface Dog extends Animal {
  breed: string;
}

// type 使用 & 交集运算符
type AnimalType = {
  name: string;
};

type DogType = AnimalType & {
  breed: string;
};
2. 声明合并能力不同
typescript 复制代码
// interface 可以重复声明,会自动合并
interface Animal {
  name: string;
}

interface Animal {
  age: number;
}

const dog: Animal = { name: '旺财', age: 1 }; // 正确

// type 不能重复声明
type AnimalType = { name: string };
// type AnimalType = { age: number }; // 错误:重复标识符
3. 应用范围不同
typescript 复制代码
// type 可以用于定义基础类型、联合类型、元组等
type ID = number | string; // 联合类型
type Point = [number, number, string]; // 元组类型
type NumberAlias = number; // 类型别名

// interface 只能描述对象结构(函数、类)
// interface ID2 = number | string; // 错误!
4. 简单类型别名
typescript 复制代码
// type 支持简单类型的别名
type NumberOther = number;
let c: NumberOther = 1;

// interface 不能为基本类型创建别名
// interface NumberInterface = number; // 错误!

2.4 如何选择:type 还是 interface?

一般建议:

  • 优先使用 interface,直到需要 type 的特定功能
  • 想定义对象结构?优先用 interface(更直观、可扩展)。
  • 需要联合类型或复杂类型?用 type
  • 大多数场景下,两者可互换,按团队习惯选择即可。

总结

让我们通过一个表格来回顾一下 type 和 interface 的主要区别:

特性 interface type
扩展方式 extends &
声明合并 ✅ 支持 ❌ 不支持
描述基本类型 ❌ 不支持 ✅ 支持
联合类型 ❌ 不支持 ✅ 支持
元组类型 ❌ 不支持 ✅ 支持
函数类型 ✅ 支持 ✅ 支持
类实现 ✅ 支持 ❌ 不支持

TypeScript 的类型系统就像是一座精妙的乐高城堡🏰,泛型、type 和 interface 是其中最重要的积木块。掌握它们,你就能构建出既安全又灵活的代码结构!

希望这篇文章能帮助你更好地理解 TypeScript 的类型系统。如果有任何问题,欢迎在评论区讨论!💬

延伸阅读:

相关推荐
崔庆才丨静觅4 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60615 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了5 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅5 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅6 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅6 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment6 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅6 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊6 小时前
jwt介绍
前端