← 返回导航

分页类型封装

业务类型 · 实战

场景说明

后台管理系统的列表页几乎都离不开分页:请求时要传页码、每页条数、排序等参数,响应时要拿到当前页数据列表和总数、总页数等元信息。把这些拆成"请求参数 / 分页元信息 / 分页数据 / 响应联合"四层类型,并用泛型参数化列表项,可以让任意实体列表(用户、订单、商品)复用同一套分页类型,杜绝字段拼写与类型错误。

完整代码


      
// 分页类型封装:请求参数、响应数据与元信息的完整分页类型设计
// 泛型化列表项类型,覆盖分页查询的全套类型

// 1. 分页请求参数
interface PaginationParams {
  page: number;            // 当前页码,从 1 开始
  pageSize: number;        // 每页条数
  sort?: string;           // 可选排序字段
  order?: 'asc' | 'desc';  // 可选排序方向
}

// 2. 分页元信息
interface PaginationMeta {
  page: number;
  pageSize: number;
  total: number;          // 总条数
  totalPages: number;    // 总页数
  hasMore: boolean;      // 是否还有下一页
}

// 3. 分页响应数据:泛型化列表项
interface PaginatedData<T> {
  list: T[];              // 当前页数据
  meta: PaginationMeta; // 分页元信息
}

// 4. 统一响应(成功/失败联合,data 泛型)
type ApiResponse<T> =
  | { code: number; message: string; data: T; success: true }
  | { code: number; message: string; data: null; success: false };

// 5. 分页 API 响应 = 统一响应 + 分页数据
type PaginatedResponse<T> = ApiResponse<PaginatedData<T>>;

interface User { id: number; name: string; }

// 应用:分页查询函数
async function fetchUsers(params: PaginationParams): Promise<PaginatedResponse<User>> {
  const res = await fetch(`/api/users?page=${params.page}&size=${params.pageSize}`);
  return res.json();
}

// 调用:用 success 收窄后访问列表与元信息
async function main() {
  const res = await fetchUsers({ page: 1, pageSize: 10, order: 'desc' });
  if (res.success) {
    res.data.list.forEach(u => console.log(u.name)); // User[]
    console.log(res.data.meta.total);                  // number
    console.log(res.data.meta.hasMore);                // boolean
  }
}

关键点解析

使用示例与类型推导


      
// 不同实体复用同一套分页类型
type UserPage = PaginatedResponse<User>;
interface Order { id: number; amount: number; }
type OrderPage = PaginatedResponse<Order>;

// 成功时 data 的结构
type DataShape = PaginatedData<User>;
// => { list: User[]; meta: PaginationMeta }

// 元信息字段推导
type Meta = PaginationMeta;
// => { page: number; pageSize: number; total: number; totalPages: number; hasMore: boolean }

// 实战:无限滚动"加载更多"判断
function canLoadMore(res: PaginatedResponse<User>): boolean {
  return res.success ? res.data.meta.hasMore : false;
}
在 Playground 中尝试