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

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

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

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

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

看起来没问题,对吧?但用着用着就发现不对劲了------我完全失去了类型信息!result1和result2都变成了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

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

​

相关推荐
2401_885885046 小时前
芬兰语音通知接口怎样对接?语音提醒接入流程
android·前端·python·php·语音识别
铁皮饭盒6 小时前
这6个小模型各有绝活, 且都可cpu/浏览器端运行
前端·后端
徐小夕7 小时前
JitKnow AI知识库 4.7 发布|多文档推理+拖拽 Agent + 技能库,打造更懂业务的 AI 知识中台
前端·vue.js·github
小poop7 小时前
从“雷峰塔”到“对象”:JavaScript基础语法入门指南
前端·javascript
ReStock活库7 小时前
Zephyr异步SPI调用返回后,为什么不能立即复用发送缓冲区?
java·前端·网络
计算机魔术师7 小时前
半年营收163亿,算力债却到7800亿,这账谁算得清
前端
chunyublog8 小时前
HDFS 上传文件名空格问题排障教程
前端·javascript·npm
?abc!8 小时前
(贪心)621. 任务调度器
java·前端·c#
摸鱼仙人~8 小时前
校招帮简历字段匹配架构分析报告
java·前端·架构
陈随易9 小时前
副业搞钱点子之赛事与活动
前端·后端·程序员