使用ES6、TypeScript和索引签名实现数据透视列转换
订单数据透视转换方案(TypeScript)
问题描述
现有如下订单数据结构:
const dataReceived: IOrder[] = [ {customerName: 'Customer 1', customerId: '1',auctionName: 'Auction 1', auctionId: '1', statusName: 'Awaiting', statusId: '1', deliveryDate: '1', orderId: '31323'}, {customerName: 'Customer 1', customerId: '1',auctionName: 'Auction 2', auctionId: '1', statusName: 'Ready', statusId: '2',deliveryDate: '1', orderId: '42423'}, {customerName: 'Customer 1', customerId: '1',auctionName: 'Auction 3', auctionId: '1', statusName: 'Ready', statusId: '2', deliveryDate: '1', orderId: '63353'}, {customerName: 'Customer 2', customerId: '2',auctionName: 'Auction 1', auctionId: '2', statusName: 'Ready', statusId: '2', deliveryDate: '1', orderId: '23232'}, {customerName: 'Customer 2', customerId: '2',auctionName: 'Auction 2', auctionId: '2', statusName: 'Awaiting', statusId: '1', deliveryDate: '1', orderId: '14433'}, {customerName: 'Customer 2', customerId: '2',auctionName: 'Auction 3', auctionId: '2', statusName: 'Ready', statusId: '2', deliveryDate: '1', orderId: '25434'}, {customerName: 'Customer 3', customerId: '3',auctionName: 'Auction 1', auctionId: '3', statusName: 'Ready', statusId: '2', deliveryDate: '1', orderId: '29332'}, {customerName: 'Customer 3', customerId: '3',auctionName: 'Auction 2', auctionId: '3', statusName: 'Awaiting', statusId: '1', deliveryDate: '1', orderId: '37364'}, {customerName: 'Customer 3', customerId: '3',auctionName: 'Auction 3', auctionId: '3', statusName: 'Awaiting', statusId: '1', deliveryDate: '1', orderId: '37112'}, ];
对应的类型定义:
export declare type IOrder = { orderId: string; deliveryDate: string; customerId: string; customerName: string; auctionId: string; auctionName: string; statusId: string; statusName: string; [key: string]: string; }
需要将数据转换为按客户聚合、以拍卖名称为动态列的结构,每个动态列对应完整的订单记录:
const dataTransformed = [ {customerName: 'Customer 1', 'Auction 1': { auctionName: 'Auction 1', customerName: 'Customer 1', statusName: 'Awaiting', orderId: '31323', ...}, 'Auction 2': { auctionName: 'Auction 2', customerName: 'Customer 1', statusName: 'Ready', orderId: '42423', ...}, 'Auction 3': { auctionName: 'Auction 3', customerName: 'Customer 1', statusName: 'Ready', orderId: '63353', ...}, ...}, {customerName: 'Customer 2', 'Auction 1': { auctionName: 'Auction 1', customerName: 'Customer 2', statusName: 'Ready', orderId: '23232', ...}, 'Auction 2': { auctionName: 'Auction 2', customerName: 'Customer 2', statusName: 'Awaiting', orderId: '14433', ...}, 'Auction 3': { auctionName: 'Auction 3', customerName: 'Customer 2', statusName: 'Ready', orderId: '25434', ...}, ...}, {customerName: 'Customer 3', 'Auction 1': { auctionName: 'Auction 1', customerName: 'Customer 3', statusName: 'Ready', orderId: '29332', ...}, 'Auction 2': { auctionName: 'Auction 2', customerName: 'Customer 3', statusName: 'Awaiting', orderId: '37364', ...}, 'Auction 3': { auctionName: 'Auction 3', customerName: 'Customer 3', statusName: 'Awaiting', orderId: '37112', ...}, ...}, ];
核心痛点:拍卖名称无法预先确定,使用TypeScript索引签名时频繁报错,需要可行的类型定义和转换方案。
解决方案
1. 定义动态类型
使用TypeScript的交叉类型结合字符串索引签名,既保留固定字段(如customerName),又支持动态的拍卖名称列:
// 定义转换后的单条数据类型 type CustomerAuctionRecord = { customerName: string; customerId: string; // 可选:如果不需要可移除 } & { [auctionName: string]: IOrder; }; // 最终转换后的数组类型 type TransformedData = CustomerAuctionRecord[];
2. 实现转换函数
通过Array.reduce按客户聚合数据,动态添加拍卖名称作为键:
function transformOrderData(orders: IOrder[]): TransformedData { return orders.reduce((acc, order) => { // 查找当前客户是否已存在于结果数组中 const existingCustomer = acc.find(item => item.customerId === order.customerId); if (existingCustomer) { // 直接添加当前拍卖对应的订单记录 existingCustomer[order.auctionName] = order; } else { // 创建新的客户记录,包含当前拍卖订单 const newCustomer: CustomerAuctionRecord = { customerName: order.customerName, customerId: order.customerId, [order.auctionName]: order } as CustomerAuctionRecord; // 类型断言处理动态键的TS检查 acc.push(newCustomer); } return acc; }, [] as TransformedData); }
3. 使用示例
const dataTransformed = transformOrderData(dataReceived); // 访问示例:获取Customer 1的Auction 1订单状态 console.log(dataTransformed[0]['Auction 1'].statusName); // 输出:Awaiting
关键说明
- 类型断言
as CustomerAuctionRecord用于绕开TypeScript对动态键的严格检查,因为拍卖名称是运行时确定的,无法提前静态推断。 - 转换后的结构完全符合表格展示需求,每个客户一行,每个拍卖作为一列,列值为完整订单信息。
内容的提问来源于stack exchange,提问作者Rob
相关产品推荐
相关产品推荐

