1

I'm trying to define a function that maps an object fields.

For instance, a tree can be stored as object. Tree node identifiers are stored as object keys. Tree nodes are stored as object field values. Each node can have an array of children identifiers.

The following function removes an item with a scpecified id from tree and also removes it from parent's children collection (for simplicity it doesn't remove children of children and so on):

type Tree = { [id: string]: { children?: string[] } };

function removeItem<T extends Tree>(tree: T, itemId: string): T {
  return Object.fromEntries(Object.entries(tree)
    .filter(([id, item]) => id !== itemId)
    .map(([id, item]) => [id, { ...item, children: item.children?.filter(child => child !== itemId) }]));
}

The usage example:

type CustomTree = { [id: string]: { name: string, children: string[] } };
const tree1: CustomTree = {};
const tree2: CustomTree = removeItem(tree1, '123');

The function should be able to process objects of a more restricted types (for instance, CustomTree).

The problem is that I get the following type error:

Type '{ [k: string]: { children: string[]; }; }' is not assignable to type 'T'.
  '{ [k: string]: { children: string[]; }; }' is assignable to the constraint of type 'T',
    but 'T' could be instantiated with a different subtype of constraint 'Tree'.

How to fix it?

1 Answer 1

2

There is a better way to achieve this.

type CustomTree = { [id: string]: { name: string; children: string[] } };

function removeItem<T extends CustomTree>(tree: T, itemId: string): T {
  const updatedTree = { ...tree };
  delete updatedTree[itemId];
  for (const key in updatedTree) {
    const index = updatedTree[key]?.children && updatedTree[key]?.children.indexOf(itemId);
    if (index !== -1) {
      updatedTree[key]?.children.splice(index as number, 1);
    }
  }
  return updatedTree;
}

const tree1: CustomTree = {
  "123": { name: "tushar", children: ["345", "567"] },
  "234": { name: "test", children: ["123", "567"] }
};

const tree2: CustomTree = removeItem(tree1, "123");
console.log(tree2);

Let me know if there is any mistakes with this code.

Here is the: Playground Link

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

1 Comment

I've got it. The idea is to copy an original object, and then modify it in-place. So there is no any typing problems. Maybe you are right, and it's easier rather than trying to deconstruct object to entries and then reconstruct them to get a new object.

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.