简体   繁体   中英

Typed group by in JavaScript/TypeScript - nested JSON to a typed nested array

I have this list in my front-end typescript file:

poMonths:

0: {id: 1, companyName: "company14", companyId: 14, flActive: true, purchaseMonth: "2019-12-15T00:00:00", purchaseMonthString: "Dec-2019" , year: 2019, month: "December"}
1: {id: 2, companyName: "company5", companyId: 5, flActive: true, purchaseMonth: "2019-12-15T00:00:00", …}
2: {id: 3, companyName: "company13", companyId: 13, flActive: true, purchaseMonth: "2019-11-15T00:00:00", …}
3: {id: 4, companyName: "company14", companyId: 14, flActive: true, purchaseMonth: "2019-11-15T00:00:00", …}
4: {id: 5, companyName: "company5", companyId: 5, flActive: true, purchaseMonth: "2019-10-15T00:00:00", …}
5: {id: 6, companyName: "company14", companyId: 14, flActive: true, purchaseMonth: "2020-09-15T00:00:00", …}
6: {id: 7, companyName: "company7", companyId: 7, flActive: true, purchaseMonth: "2020-09-15T00:00:00", …}

I would like to get a nested typed tree out of it, something similar to this but in a typed format:

在此处输入图片说明

So I am using this function to group the list to what I want:

groupBy() {
    const result = this.poMonths.reduce((state, current) => {
      const { companyName, year, month } = current;

      const company = state[companyName] || (state[companyName] = {});
      const yearObj = company[year] || (company[year] = {});
      const monthArr = yearObj[month] || (yearObj[month] = []);

      monthArr.push(current);


      return state;
    }, {});
    return result;
  }

However, the returned value is not typed, it is just a JSON object. How can I make it typed utilizing these types for instance?:

export class ItemNode {
  children: ItemNode[];
  item: string;
}

/** leaf item node with database id information. each leaf will be a single leaf containing an id from the database */
export class LeafItemNode {
  id?: number;
  companyId: number;
  companyName: string;
  flActive: boolean;
  purchaseMonth: Date;
  purchaseMonthString: string;
  year: number;
  month: number;
}

Basically, the tree should consist of ItemNodes all the way down to the leaves which would be LeafItemNode (containing the IDs)

You can keep using .reduce() however now you have to start with an array as inital object:

let initialState: ItemNode[] = [];

const result: ItemNode[] = input.reduce((state, current) => {
    const { companyName, year, month } = current;

        let company = state.find(x => x.item == companyName);
        if (!company) {
            company = new ItemNode();
            company.item = companyName;
            company.children = [];
            state.push(company);    
        }

        let yearObj = company.children.find(x => x.item == year.toString());
        if (!yearObj) {
            yearObj = new ItemNode();
            yearObj.item = year.toString();
            yearObj.children = [];
            company.children.push(yearObj);               
        } 

        let monthObj = yearObj.children.find(x => x.item == month.toString());
        if (!monthObj) {
            monthObj = new ItemNode();
            monthObj.item = month.toString();
            monthObj.children = [];
            yearObj.children.push(monthObj);
        }

        let cur = new ItemNode();
        cur.item = id.toString();
        monthObj.children.push(cur);

        return state;
}, initialState);

JS testable version:

 class ItemNode {} let input = [{id: 1, companyName: "company14", companyId: 14, flActive: true, purchaseMonth: "2019-12-15T00:00:00", year: 2019, month: "December"}, {id: 2, companyName: "company5", companyId: 5, flActive: true, purchaseMonth: "2019-12-15T00:00:00", year: 2019, month: "December"}, {id: 3, companyName: "company13", companyId: 13, flActive: true, purchaseMonth: "2019-11-15T00:00:00", year: 2019, month: "November"}, {id: 4, companyName: "company14", companyId: 14, flActive: true, purchaseMonth: "2019-11-15T00:00:00", year: 2019, month: "December"}, {id: 5, companyName: "company5", companyId: 5, flActive: true, purchaseMonth: "2019-10-15T00:00:00", year: 2019, month: "October"}, {id: 6, companyName: "company14", companyId: 14, flActive: true, purchaseMonth: "2020-09-15T00:00:00", year: 2020, month: "September"}, { id: 7, companyName: "company7", companyId: 7, flActive: true, purchaseMonth: "2020-09-15T00:00:00", year: 2020, month: "September" }] let initialState = []; const result = input.reduce((state, current) => { const { id, companyName, year, month } = current; let company = state.find(x => x.item == companyName); if (!company) { company = new ItemNode(); company.item = companyName; company.children = []; state.push(company); } let yearObj = company.children.find(x => x.item == year.toString()); if (!yearObj) { yearObj = new ItemNode(); yearObj.item = year.toString(); yearObj.children = []; company.children.push(yearObj); } let monthObj = yearObj.children.find(x => x.item == month.toString()); if (!monthObj) { monthObj = new ItemNode(); monthObj.item = month.toString(); monthObj.children = []; yearObj.children.push(monthObj); } let cur = new ItemNode(); cur.item = id.toString(); monthObj.children.push(cur); return state; }, initialState); console.log(result);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM