Типизированная группа в JavaScript / TypeScript - вложенная JSON в типизированный вложенный массив - PullRequest
1 голос
/ 15 января 2020

У меня есть этот список в моем файле машинописи внешнего интерфейса:

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", …}

Я хотел бы получить из него вложенное типизированное дерево что-то похожее на это, но в типизированном формате:

enter image description here

Так что я использую эту функцию для группировки списка к тому, что я хочу:

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

Однако возвращаемое значение не печатается, это просто объект JSON. Как я могу сделать его типизированным, используя эти типы, например?:

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

По сути, дерево должно состоять из ItemNodes вплоть до листьев, которые будут LeafItemNode (содержащие идентификаторы)

1 Ответ

1 голос
/ 15 января 2020

Вы можете продолжать использовать .reduce(), однако теперь вам нужно начинать с массива в качестве начального объекта:

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 тестируемая версия:

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