1

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:

enter image description here

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)

1 Answer 1

1

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);

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.