TS泛型:让类型也学会“套娃”,但这次很优雅

大家好,我是小杨。今天想和大家聊聊TypeScript中让我又爱又恨的一个特性------泛型。

记得我第一次接触泛型时,看着那一对尖括号<>,心里直犯嘀咕:这玩意儿到底有啥用?直到我在项目中写了这样的代码:

typescript 复制代码
// 最初的我:使用any大法
function identity(value: any): any {
    return value;
}

const result1 = identity("hello"); // result1的类型是any
const result2 = identity(42);      // result2的类型也是any

看起来没问题,对吧?但用着用着就发现不对劲了------我完全失去了类型信息!result1result2都变成了any,TypeScript的所有优势荡然无存。

泛型来救场了!

泛型就像是给函数、类或接口的一个"类型参数",让我们在使用时才确定具体的类型:

typescript 复制代码
// 现在的我:使用泛型
function identity<T>(value: T): T {
    return value;
}

const result1 = identity("hello"); // result1的类型是string!
const result2 = identity(42);      // result2的类型是number!

看到了吗?TypeScript自动推断出了返回值的具体类型,这就是泛型的魔力!

泛型的几种实用场景

1. 处理数组不再头疼

typescript 复制代码
// 以前处理数组很麻烦
function getFirstElement(arr: any[]): any {
    return arr[0];
}

// 现在可以这样
function getFirstElement<T>(arr: T[]): T | undefined {
    return arr[0];
}

const stringArray = ["apple", "banana", "cherry"];
const numberArray = [1, 2, 3];

const firstString = getFirstElement(stringArray); // 类型是string
const firstNumber = getFirstElement(numberArray); // 类型是number

2. 让接口也"通用"起来

typescript 复制代码
// 一个通用的API响应接口
interface ApiResponse<T> {
    code: number;
    message: string;
    data: T;
    timestamp: Date;
}

// 用户数据
interface User {
    id: number;
    name: string;
    email: string;
}

// 商品数据  
interface Product {
    id: number;
    title: string;
    price: number;
}

// 现在可以这样使用
const userResponse: ApiResponse<User> = {
    code: 200,
    message: "success",
    data: {
        id: 1,
        name: "张三",
        email: "zhangsan@example.com"
    },
    timestamp: new Date()
};

const productResponse: ApiResponse<Product> = {
    code: 200, 
    message: "success",
    data: {
        id: 101,
        title: "笔记本电脑",
        price: 5999
    },
    timestamp: new Date()
};

3. 约束泛型:给类型加个"边界"

有时候我们希望泛型有一定的限制,不是随便什么类型都可以:

typescript 复制代码
// 要求传入的对象必须有length属性
interface HasLength {
    length: number;
}

function logLength<T extends HasLength>(item: T): void {
    console.log(`Length: ${item.length}`);
}

logLength("hello");     // ✅ 字符串有length
logLength([1, 2, 3]);   // ✅ 数组有length  
logLength({ length: 5 }); // ✅ 对象有length属性
// logLength(42);       // ❌ 数字没有length属性

4. 多个泛型参数

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

const person = {
    name: "李四",
    age: 30,
    email: "lisi@example.com"
};

const personName = getProperty(person, "name");    // string类型
const personAge = getProperty(person, "age");      // number类型
// getProperty(person, "height");                  // ❌ 没有height这个属性

我在实际项目中的泛型应用

让我分享一个在真实项目中很有用的例子:

typescript 复制代码
// 分页查询的通用类型
interface PaginationParams {
    page: number;
    pageSize: number;
}

interface PaginationResult<T> {
    data: T[];
    total: number;
    currentPage: number;
    totalPages: number;
    hasNext: boolean;
}

async function paginateQuery<T>(
    params: PaginationParams,
    fetchData: (params: PaginationParams) => Promise<T[]>,
    countData: () => Promise<number>
): Promise<PaginationResult<T>> {
    const [data, total] = await Promise.all([
        fetchData(params),
        countData()
    ]);
    
    return {
        data,
        total,
        currentPage: params.page,
        totalPages: Math.ceil(total / params.pageSize),
        hasNext: params.page < Math.ceil(total / params.pageSize)
    };
}

// 使用示例
interface Article {
    id: number;
    title: string;
    content: string;
}

// 查询文章列表
const articleResult = await paginateQuery<Article>(
    { page: 1, pageSize: 10 },
    fetchArticles,
    countArticles
);
// articleResult.data 的类型是 Article[]

我的心得体会

泛型学习有个过程,我总结了几点经验:

  1. 从简单开始 :先理解<T>的基本概念,不要一开始就追求复杂的高级用法
  2. 多用多练:在合适的场景刻意使用泛型,慢慢就会找到感觉
  3. 适度使用:不是所有地方都需要泛型,在真正需要通用性的地方使用它
  4. 善用约束 :用extends给泛型加上合理的限制,避免滥用

泛型就像是TypeScript中的"万能钥匙",一旦掌握,就能写出既灵活又类型安全的代码。它让我们的类型系统从"死板"变得"智能",这才是TypeScript真正的威力所在!

希望这篇分享能帮你打开泛型的大门。如果你在学习过程中有什么心得体会,欢迎在评论区交流讨论!

⭐ 写在最后

请大家不吝赐教,在下方评论或者私信我,十分感谢🙏🙏🙏.

✅ 认为我某个部分的设计过于繁琐,有更加简单或者更高逼格的封装方式

✅ 认为我部分代码过于老旧,可以提供新的API或最新语法

✅ 对于文章中部分内容不理解

✅ 解答我文章中一些疑问

✅ 认为某些交互,功能需要优化,发现BUG

✅ 想要添加新功能,对于整体的设计,外观有更好的建议

✅ 一起探讨技术加qq交流群:906392632

最后感谢各位的耐心观看,既然都到这了,点个 👍赞再走吧!

相关推荐
Jing_Rainbow2 分钟前
【AI-5 全栈-1 /Lesson9(2025-10-29)】构建一个现代前端 AI 图标生成器:从零到完整实现 (含 AIGC 与后端工程详解)🧠
前端·后端
阿明Drift8 分钟前
用 RAG 搭建一个 AI 小说问答系统
前端·人工智能
1***s63214 分钟前
React区块链开发
前端·react.js·区块链
wordbaby14 分钟前
赋值即响应:深入剖析 Riverpod 的“核心引擎”
前端·flutter
南山安15 分钟前
HTML5 自定义属性 data-*:别再把数据塞进 class 里了!
前端·javascript·代码规范
努力的白熊嗨15 分钟前
大文件 Hash 计算:Web Worker 并行优化的原理与局限性
javascript·算法
T___T16 分钟前
深入浅出:JavaScript 字符串反转的 6 种解法与面试技巧
javascript·面试
HuangYongbiao19 分钟前
Rspack Loader 架构原理:从 Loader Runner 到 Rust Loader Pipeline
前端·架构
hen3y22 分钟前
基于 jscodeshift 构建高效 Codemod 工具指南
前端·javascript
烛阴25 分钟前
代码的灵魂:C# 方法全景解析(万字长文,建议收藏)
前端·c#