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

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

相关推荐
西洼工作室8 小时前
vue2+vuex登录功能
前端·javascript·vue.js
IT_陈寒8 小时前
Spring Boot 3.2性能翻倍!我仅用5个技巧就让接口响应时间从200ms降到50ms
前端·人工智能·后端
艾小码8 小时前
从写原生JS到玩转框架:我走过的那些弯路和顿悟时刻
前端·javascript
初遇你时动了情12 小时前
css中backdrop-filter 详细使用 ios毛玻璃效果、filter和backdrop-filter使用说明
前端·css
景彡先生13 小时前
Python Selenium详解:从入门到实战,Web自动化的“瑞士军刀”
前端·python·selenium
Liudef0615 小时前
DeepseekV3.2 实现构建简易版Wiki系统:从零开始的HTML实现
前端·javascript·人工智能·html
景早16 小时前
vue 记事本案例详解
前端·javascript·vue.js
wangjialelele17 小时前
Qt中的常用组件:QWidget篇
开发语言·前端·c++·qt
乔冠宇18 小时前
vue需要学习的点
前端·vue.js·学习