-1

I have an object with type:

export interface TreeNode extends ITreeNode {
   name: string,
   children:  TreeNode[],
   show?: boolean;
}

I need to reduce this object by property show and return a new tree where show is true or undefined.

I have tried this:

  function prepareNodes(source: TreeNode) {
        if (source.show!== undefined || source.show == false) delete source;
      if (source.children) {
        source.children.forEach((child: TreeNode) => {
          this.prepareNodes(child);
        });
      }
  }

Also I tried:

function prepareNodes(source: any) {
      if (source.show !== undefined && source.show === false) source = null;
      if (source.children) {
        source.children = source.children.filter((child: any) => child.show== undefined || child.show === true);
        source.children.forEach((child: any) => prepareNodes(child));
      }
  }
  • Updated my question –  Feb 11 '21 at 16:32
  • What do you expect the output to be? What is the output the function is giving at the moment? – evolutionxbox Feb 11 '21 at 16:34
  • `show` cannot be `undefined` by your own definition of it. – Randy Casburn Feb 11 '21 at 16:34
  • that makes it worse!! Now your entire premise of reducing is based upon an optional property - not one that will always either be true, false or undefined. You've created a case where `show` may not even exist but not accounted for that. – Randy Casburn Feb 11 '21 at 16:36
  • I know, it is, but is my case, I should check on undefined/true/false as I posted –  Feb 11 '21 at 16:38
  • 1
    Can you please post some sample data? – user991047 Feb 11 '21 at 16:41
  • Is your whole issue that you're doing `delete source` instead of `delete source.show`? Are you tying to modify the existing tree or produce a new tree? Are you trying to have the output tree known to be `true | undefined` by the compiler? Or is `boolean | undefined` acceptable as the output type? – jcalz Feb 11 '21 at 16:42
  • 1
    [`delete source` does not do what you think it does](https://stackoverflow.com/q/8945276/215552)... – Heretic Monkey Feb 11 '21 at 16:43
  • Ideally you'd post a [mcve] suitable for dropping into a standalone IDE like [The TypeScript Playground](https://tsplay.dev/zwOoyw) where the issue you're having is clearly demonstrated and no extraneous issues are present (no typos, no undeclared or unimported things). Right now there's not quite enough for me to feel confident answering. – jcalz Feb 11 '21 at 16:43
  • So, I see only way to create a new tree after filtrering –  Feb 11 '21 at 16:44
  • Oof, `source.show!== undefined || source.show == false` is.. weird. If `source.show` is `true` or `false`, that evaluates to `true`. If `source.show` is `undefined`, that evaluates to `false`. So you're checking if `source.show` is either `true` or `false` for some reason, and not `undefined`. What is happening here? I strongly suggest you modify the example code so that it represents what you're trying to do as closely as you can, and show enough use cases so others can figure out what constitutes success. And what's `registry`? I think we need some cleanup here. – jcalz Feb 11 '21 at 16:49
  • `Undefined` is in casw when there is a property in object, false can be when `show: false` and `show: true.` –  Feb 11 '21 at 16:50
  • I'm not following, sorry. Could you be more explicit in the text of your question? And again, a [mcve] is crucial here. At this point I don't even understand if you want `show: true` in the input to become `show: true` in the output. I was assuming you wanted `true` to become `true`, and `false`-or-`undefined` to become `undefined`. Like [this code](https://tsplay.dev/PmLoeN). Now I'm thoroughly confused. – jcalz Feb 11 '21 at 16:57

1 Answers1

0

Currently my assumption is that you want to produce a new tree containing just those nodes of the original tree where the show property is either true or undefined for that node and all ancestor nodes. So if show is false on any node, the output tree will not contain that node or any subtree of that node.

I also assume that it's possible for the root node to have show of false, in which case the whole tree might end up undefined. You can't set modify an object to become undefined; you can change its contents, but you can't delete it. So I'm not going to present anything that tries to modify the original tree. I won't touch the original tree. Instead I will produce a completely new tree.

Here goes:

const defined = <T,>(x: T | undefined): x is T => typeof x !== "undefined";

function filterTree(source: TreeNode): TreeNode | undefined {
  if (source.show === false) return;
  return {
    name: source.name,
    show: source.show,
    children: source.children.map(filterTree).filter(defined)
  }
}

The filterTree() function will return undefined if the argument node's show property is exactly false (and not undefined). Otherwise, it produces a new node with the same name and show, and whose children property is what you get when you call filterTree() (recursively) on each of the original node's children, and then filter out any undefined nodes.

I'm using a user-defined type guard function called defined to let the compiler know that the filtering takes an array of TreeNode | undefined and produces an array of TreeNode, eliminating any undefined entries.

Hopefully this meets your use cases; please test it out on whatever data you have and check, because the question unfortunately did not include such data.

Playground link to code

jcalz
  • 264,269
  • 27
  • 359
  • 360
  • Could I use this: `return { ...source, children: source.children.map(filterTree).filter(defined) }`? –  Feb 11 '21 at 17:21
  • Yes, if you want. – jcalz Feb 11 '21 at 17:23
  • How to post link from typescript playground? it is so long –  Feb 11 '21 at 17:30
  • Where do you want to post it? You can put it in your question with the link syntax `[text](url)`. Or if you install the Link Shortener plugin on the Playground you can generate short links for them, but I don't know how to walk you through that process over the internet. – jcalz Feb 11 '21 at 17:32
  • Look it does not work for property registry: https://stackblitz.com/edit/xy4wiq?file=index.ts –  Feb 11 '21 at 17:33
  • Can you modify that code to spell out exactly what you expect to see and where? All I see is "Import error, can't find file:" – jcalz Feb 11 '21 at 17:37
  • I try to show nodes where registry is true or undefined. The same situation –  Feb 11 '21 at 17:38
  • Check out this: https://typescript-isam5f.stackblitz.io –  Feb 11 '21 at 17:40
  • This node with `id": "37_1",` should not be in result object –  Feb 11 '21 at 17:40
  • all I see at that link is "starting dev server". I don't understand why `37_1` should not be in there; I am showing all with `true` or `undefined` and suppressing `false`. `37_1` is not defined, so it's shown. `undefined` makes it shown. I need clear instructions in English before I can continue to engage here. – jcalz Feb 11 '21 at 17:44
  • Let me check please, probably I disinformation you –  Feb 11 '21 at 17:44