当前位置: 首页 > news >正文

TypeScript 泛型 T 详细解释

什么是泛型

  • T 是一个类型变量,代表"某种类型"

举个例子

  • loadMore: (page: number) => Promise<T[]>;
  • 相当于说:这个函数返回一个Promise,Promise解析的结果是T类型的数组

实际使用时的具体化

// 当 T = Product 时:
loadMore: (page: number) => Promise<Product[]>;// 当 T = string 时:
loadMore: (page: number) => Promise<string[]>;// 当 T = User 时:
loadMore: (page: number) => Promise<User[]>;

在组件中的完整应用

// 定义泛型组件
interface InfiniteScrollProps<T = any> {loadMore: (page: number) => Promise<T[]>;  // T 在这里定义renderItem: (item: T, index: number) => React.ReactNode;  // 这里也用 T
}// 使用泛型组件时,T 会被具体类型替换
function ProductList() {return (<InfiniteScroll<Product>  // 这里明确指定 T = ProductloadMore={fetchProducts}  // 现在这个函数需要返回 Promise<Product[]>renderItem={(product) => (  // 这里的 product 自动就是 Product 类型<div>{product.name} - ${product.price}</div>)}/>);
}

举个例子

用户数据

// 定义用户类型
interface User {id: number;name: string;email: string;avatar: string;
}function UserList() {// 加载用户数据的函数 - 必须返回 User[]const loadUsers = async (page: number): Promise<User[]> => {const response = await fetch(`/api/users?page=${page}`);const data = await response.json();return data.users; // 这里必须是 User[] 类型};// 渲染用户项 - item 自动推断为 User 类型const renderUser = (user: User) => (<div className="user-card"><img src={user.avatar} alt={user.name} /><h3>{user.name}</h3><p>{user.email}</p></div>);return (<InfiniteScroll<User>  // 明确指定类型loadMore={loadUsers}renderItem={renderUser}/>);
}

文章数据

// 定义文章类型
interface Article {id: string;title: string;content: string;author: string;createdAt: Date;
}function ArticleList() {const loadArticles = async (page: number): Promise<Article[]> => {const response = await fetch(`/api/articles?page=${page}`);return response.json(); // 返回 Article[]};const renderArticle = (article: Article) => (<article><h2>{article.title}</h2><p>By {article.author}</p><div>{article.content}</div></article>);return (<InfiniteScroll<Article>loadMore={loadArticles}renderItem={renderArticle}/>);
}

类型自动推断

  • 如果不显式指定 ,TypeScript 会尝试自动推断:
function Example() {// TypeScript 会根据 loadMore 的返回值推断 T = Productconst loadMore = async (page: number): Promise<Product[]> => {// ...};// 这里不需要显式写 <Product>return (<InfiniteScrollloadMore={loadMore}  // TypeScript 知道这里 T = ProductrenderItem={(product) => {  // product 自动就是 Product 类型product.id;    // ✅ 正确product.name;  // ✅ 正确  product.abc;   // ❌ 错误:Product 类型没有 abc 属性}}/>);
}

泛型的优势

类型安全

interface Product {id: number;name: string;price: number;
}// 如果 loadMore 返回了错误类型,TypeScript 会报错
const loadMore = async (page: number): Promise<Product[]> => {return [{ id: 1, name: "Phone", price: 999 },{ id: 2, name: "Tablet", price: 699 },{ id: 3, name: "Laptop" } // ❌ 错误:缺少 price 属性];
};

智能提示

const renderItem = (product: Product) => {// 编辑器会提供 Product 的所有属性提示:product. // 输入 . 后会提示:id, name, price
};

复杂类型示例

嵌套对象

interface Post {id: number;title: string;author: {id: number;name: string;avatar: string;};tags: string[];
}function PostList() {const loadMore = async (page: number): Promise<Post[]> => {// 必须返回 Post[] 类型};const renderItem = (post: Post) => (<div><h3>{post.title}</h3><img src={post.author.avatar} alt={post.author.name} /><div>{post.tags.map(tag => (<span key={tag}>{tag}</span>))}</div></div>);return (<InfiniteScroll<Post>loadMore={loadMore}renderItem={renderItem}/>);
}

默认类型

  • 在类型定义中,我们可以给泛型一个默认类型:
// T = any 表示如果不指定类型,就使用 any
interface InfiniteScrollProps<T = any> {loadMore: (page: number) => Promise<T[]>;renderItem: (item: T, index: number) => React.ReactNode;
}// 这样使用时,T 就是 any 类型(不推荐,失去类型安全)
function AnyList() {return (<InfiniteScroll  // 没有指定 <T>loadMore={async (page) => [{ anything: 'here' }]}  // 返回 any[]renderItem={(item) => (<div>{item.anything}     // ✅ 不会报错,但也没有类型提示{item.something}    // ✅ 也不会报错</div>)}/>);
}

总结

  • 是 TypeScript 的泛型参数,代表"某种类型"
  • T[] 表示"T类型的数组"
  • Promise<T[]> 表示"异步返回T类型数组的Promise"
  • 使用泛型让组件类型安全且灵活
  • 在实际使用时,T 会被具体的类型(如 Product, User 等)替换
  • 这样设计的好处是:一次编写,多种类型复用,同时保持完整的类型检查和智能提示。
http://www.hskmm.com/?act=detail&tid=21745

相关文章:

  • day007
  • 【Rust GUI开发入门】编写一个本地音乐播放器(12. 国际化应用-多语言支持) - Jordan
  • 2025秋_6
  • 程序语言杂谈:C/C++
  • 2025秋_7
  • PEP8 规范
  • print() 函数
  • 第九天
  • Pycharm 设置
  • [NOIP 2016 提高组] 组合数问题
  • 新建第一个项目
  • 笛卡尔树 (区间最小值)
  • CF2003F. Turtle and Three Sequences
  • 【Rust GUI开发入门】编写一个本地音乐播放器(11. 支持动态明暗主题切换) - Jordan
  • 利用接口中的静态虚拟成员实现自定义配置节
  • 天线增益与有源接收面积之间的关系
  • 2025CSP-S晋级和英才计划入围后:我走过了哪些路
  • 流量分析
  • fdsaf -
  • 【J+S 二十连测】-- 第十二套爆炸记
  • 2025-2026-1 CS3311 软件工程 个人项目第一版已发布
  • Python浅拷贝、深拷贝
  • 破解 Pycharm
  • 阿里业务身份建模
  • 实用指南:矩阵结构体 图片绘制 超级玛丽demo6
  • 5分钟理清:Session、JWT、Token、SSO、OAuth 2.0 认证逻辑
  • 2025年10.1~10.6日信息竞赛计划安排表
  • 【Rust GUI开发入门】编写一个本地音乐播放器(10. 拼装UI组件) - Jordan
  • 国产数据库-达梦docker镜像安装
  • CAP 8.4 版本发布通告