'I want to designate a type according to the conditions of the object property

There is organizational data with a hierarchical structure.

Organizational nodes are divided into Root, Dept, and User.

The object property type is assigned a type suitable for node data.

So, I hope that the node interface suitable for the object type will be attached conditionally.

To solve this problem, I tried Index Types and Conditional Types, but they were not successful.

Any help would be appreciated🙇‍♂️

export enum NodeType {
  root = "root",
  dept = "dept",
  user = "user",
}

interface Node {
  readonly nodeId: string;
  readonly type: NodeType;
  title: string;
  childNodes?: Node[];
}

interface RootNode extends Node {
  type: NodeType.root;
  childNodes?: (DeptNode | UserNode)[];
}

interface DeptNode extends Node {
  type: NodeType.dept;
  childNodes?: (DeptNode | UserNode)[];

  deptId: string;
  companyCode: string;
}

interface UserNode extends Node {
  type: NodeType.user;
  childNodes?: UserNode[];

  employeeNumber: string;
  userPrincipalName: string;
}

/**
 * from hierarchy data to flatting data
 */
function flatting(st: Node) {
  flatCompanyData.push(st);
  if (st.childNodes) {
    st.childNodes.forEach((x) => flatting(x));
  }
}

const companyData: RootNode = {
  nodeId: "0",
  type: NodeType.root,
  title: "Company 1",
  childNodes: [
    {
      nodeId: "0.0",
      type: NodeType.dept,
      title: "Department 1",
      deptId: "A1",
      companyCode: "557",
      childNodes: [
        {
          nodeId: "0.0.0",
          type: NodeType.user,
          title: "User 1",
          employeeNumber: "201911",
          userPrincipalName: "[email protected]",
        },
        {
          nodeId: "0.0.1",
          type: NodeType.user,
          title: "User 2",
          employeeNumber: "201912",
          userPrincipalName: "[email protected]",
        },
      ],
    },
    {
      nodeId: "0.1",
      type: NodeType.dept,
      title: "Department 2",
      deptId: "A2",
      companyCode: "558",
    },
  ],
};
let flatCompanyData: Node[] = [];

flatting(companyData);

// I want to be the type of DeptNode interface because the type of object property is NodeType.dept.
const selectDept = flatCompanyData.filter((x) => x.type === NodeType.dept);
selectDept.forEach((x) => {
  console.log({
    nodeId: x.nodeId,
    type: x.type,
    title: x.title,
    // The type is not affirmed in the node that fits the object property type, so you have to affirm the type yourself.
    deptId: (x as DeptNode).deptId,
    companyCode: (x as DeptNode).companyCode,
  });
});

// I want to be the type of UserNode interface because the type of object property is NodeType.user.
const selectUser = flatCompanyData.filter((x) => x.type === NodeType.user);
selectUser.forEach((x) => {
  console.log({
    nodeId: x.nodeId,
    type: x.type,
    title: x.title,
    // The type is not affirmed in the node that fits the object property type, so you have to affirm the type yourself.
    employeeNumber: (x as UserNode).employeeNumber,
    userPrincipalName: (x as UserNode).userPrincipalName,
  });
});


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source