# Env.get() is declared to return a string, but in subflows, it doesn't

**URL:** <https://discourse.nodered.org/t/env-get-is-declared-to-return-a-string-but-in-subflows-it-doesnt/74757>\
**Category:** General\
**Tags:** function-node\
**Created:** [5 February 2023 23:11 UTC](https://discourse.nodered.org/t/env-get-is-declared-to-return-a-string-but-in-subflows-it-doesnt/74757 "2023-02-05T23:11:19Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![Putzeimer](https://avatars.discourse-cdn.com/v4/letter/p/a9a28c/32.png) [@Putzeimer](https://discourse.nodered.org/u/Putzeimer)\
**Post date:** [5 February 2023 23:11 UTC](https://discourse.nodered.org/t/env-get-is-declared-to-return-a-string-but-in-subflows-it-doesnt/74757/1 "2023-02-05T23:11:19Z")

</div>

Hi,  
a subflow has the environment variable `List` set to type JSON. The value of this variable is set to:

```auto
["foo","bar"]

```

The variable is retrieved in a function node inside the subflow via `env.get()`. When I hover over the `get` in the integrated monaco editor, the online help shows up and tells me that this function returns a `string`.

But with the lines:

```auto
node.warn(typeof env.get('List'));
node.warn(Array.isArray(env.get('List')));

```

I get: `"object"` and `true`.

When I then try to iterate through the array by typing

```auto
for (let i in env.get('List'))

```

the editor marks `env.get('List')` with this error:  
`The right-hand side of a 'for...in' statement must be of type 'any', an object type or a type parameter, but here has type 'string'.(2407)`  
That's true, if `env.get()` would really return a string, but it doesn't. If I ignore the warning and deploy anyway, the code works as expected.

I guess the functions return value was updated at some time, but the definition, the editor uses, was not?

node-red v3.0.2  
node.js v16.19.0

Here's a sample (sub)flow:

> **Example flow:**
>
> ```auto
> [
> {
> "id": "85f46028b8243fab",
> "type": "subflow",
> "name": "Subflow 1",
> "info": "",
> "category": "",
> "in": [
> {
> "x": 120,
> "y": 60,
> "wires": [
> {
> "id": "c9861e59b0f13953"
> }
> ]
> }
> ],
> "out": [],
> "env": [
> {
> "name": "List",
> "type": "json",
> "value": ""
> }
> ],
> "meta": {},
> "color": "#DDAA99"
> },
> {
> "id": "c9861e59b0f13953",
> "type": "function",
> "z": "85f46028b8243fab",
> "name": "function 1",
> "func": "let List = env.get('List');\nnode.warn(typeof List);\nnode.warn(Array.isArray(List));\nnode.warn(List);\nfor (let i in List)\n node.warn(List[i]);\nreturn msg;",
> "outputs": 1,
> "noerr": 0,
> "initialize": "",
> "finalize": "",
> "libs": [],
> "x": 240,
> "y": 60,
> "wires": [
> []
> ]
> },
> {
> "id": "3c7ce0954fc376d7",
> "type": "subflow:85f46028b8243fab",
> "z": "d49e15e1b5f5352d",
> "name": "",
> "env": [
> {
> "name": "List",
> "value": "[\"foo\",\"bar\"]",
> "type": "json"
> }
> ],
> "x": 620,
> "y": 180,
> "wires": []
> },
> {
> "id": "da28e302f3f3b142",
> "type": "inject",
> "z": "d49e15e1b5f5352d",
> "name": "",
> "props": [
> {
> "p": "payload"
> },
> {
> "p": "topic",
> "vt": "str"
> }
> ],
> "repeat": "",
> "crontab": "",
> "once": false,
> "onceDelay": 0.1,
> "topic": "",
> "payload": "",
> "payloadType": "date",
> "x": 460,
> "y": 180,
> "wires": [
> [
> "3c7ce0954fc376d7"
> ]
> ]
> }
> ]
> 
> ```

---

<div class="post-metadata">

**Author:** ![E1cid](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/e1cid/32/77971_2.png) [@E1cid](https://discourse.nodered.org/u/E1cid)\
**Post date:** [6 February 2023 09:03 UTC](https://discourse.nodered.org/t/env-get-is-declared-to-return-a-string-but-in-subflows-it-doesnt/74757/2 "2023-02-06T09:03:05Z")

</div>

`for in` is for objects an will return the keys of the object. For an array use `for of`

> **[for...of - JavaScript | MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of)**
>
> The for...of statement executes a loop that operates on a sequence of values sourced from an iterable object. Iterable objects include instances of built-ins such as Array, String, TypedArray, Map, Set, NodeList (and other DOM collections), as well...

---

<div class="post-metadata">

**Author:** ![Putzeimer](https://avatars.discourse-cdn.com/v4/letter/p/a9a28c/32.png) [@Putzeimer](https://discourse.nodered.org/u/Putzeimer)\
**Post date:** [6 February 2023 12:14 UTC](https://discourse.nodered.org/t/env-get-is-declared-to-return-a-string-but-in-subflows-it-doesnt/74757/3 "2023-02-06T12:14:20Z")

</div>

An array _is_ an object. I use `for...in` if I need the index inside the loop and `for...of` otherwise.

Btw: otherwise than stated in the error message, `for...in` is indeed able to iterate over a string:

```auto
let foo = 'bar';
for (let i in foo)
	node.warn('foo[' + i + '] = ' + foo[i]);

```

Output:

```auto
"foo[0] = b"
"foo[1] = a"
"foo[2] = r"

```

The editor will show up with the same error. I think this is another issue (perhaps related to monaco?).

Anyway, the point of this posting is, that the `env.get()` is declared to always return a string which isn't correct.  
I appreciate that `env.get()` returns the actual type instead of casting everything to a string, but the editor should know about that fact.

---

<div class="post-metadata">

**Author:** ![E1cid](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/e1cid/32/77971_2.png) [@E1cid](https://discourse.nodered.org/u/E1cid)\
**Post date:** [6 February 2023 12:40 UTC](https://discourse.nodered.org/t/env-get-is-declared-to-return-a-string-but-in-subflows-it-doesnt/74757/4 "2023-02-06T12:40:31Z")

</div>

technically a javascript array is an object, but most make the distinction of object(dictionary) as object and object(array) as an array.

Not sure what your subflow env var is returned as, will take a look if you export an example flow.

If you want the env var to return a string set it as a string not json

---

<div class="post-metadata">

**Author:** ![Putzeimer](https://avatars.discourse-cdn.com/v4/letter/p/a9a28c/32.png) [@Putzeimer](https://discourse.nodered.org/u/Putzeimer)\
**Post date:** [6 February 2023 13:07 UTC](https://discourse.nodered.org/t/env-get-is-declared-to-return-a-string-but-in-subflows-it-doesnt/74757/5 "2023-02-06T13:07:26Z")

</div>

> [@E1cid](#):
>
> will take a look if you export an example flow

An example flow is already added at the end of the original post.

> [@E1cid](#):
>
> If you want the env var to return a string set it as a string not json

No, I want `env.get()` to return JSON. The problem is that the editor _thinks_ that the function returns a string.

---

<div class="post-metadata">

**Author:** ![E1cid](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/e1cid/32/77971_2.png) [@E1cid](https://discourse.nodered.org/u/E1cid)\
**Post date:** [6 February 2023 13:11 UTC](https://discourse.nodered.org/t/env-get-is-declared-to-return-a-string-but-in-subflows-it-doesnt/74757/6 "2023-02-06T13:11:35Z")

</div>

I don't download text docs to my computer.

To share a flow use the \</\> button and paste it between tha backticks, Then all anyone needs to do is hit the copy icon, no download or extra clicks or having to delete a file.  
e.g.

```auto
[{"id":"01cd665373cb4cef","type":"subflow","name":"Subflow 1","info":"","category":"","in":[{"x":40,"y":80,"wires":[{"id":"fefb4c0d6c852023"}]}],"out":[{"x":340,"y":80,"wires":[{"id":"fefb4c0d6c852023","port":0}]}],"env":[{"name":"list_string","type":"str","value":"{\"test\":\"tester\"}","ui":{"label":{"en-US":"Enter Topic Suffix"},"type":"input","opts":{"types":["str"]}}},{"name":"list_array","type":"json","value":"{\"test\":\"tester\"}"}],"meta":{},"color":"#DDAA99"},{"id":"fefb4c0d6c852023","type":"function","z":"01cd665373cb4cef","name":"function 12","func":"const list_string = env.get(\"list_string\");\nconst list_array = env.get(\"list_array\") ;\nmsg.payload = { \"string\": list_string, \"array\": list_array};\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":190,"y":80,"wires":[[]]},{"id":"938f0bc5c5f1f3c5","type":"inject","z":"da8a6ef0b3c9a5c8","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":100,"y":4720,"wires":[["d093ee9769e932b6"]]},{"id":"d093ee9769e932b6","type":"subflow:01cd665373cb4cef","z":"da8a6ef0b3c9a5c8","name":"","x":260,"y":4720,"wires":[["72fd6ce6c8e5692e"]]},{"id":"72fd6ce6c8e5692e","type":"debug","z":"da8a6ef0b3c9a5c8","name":"debug 231","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":530,"y":4620,"wires":[]}]

```

You can tell monaco to ignore the error add `// @ts-ignore` before the env line.

---

<div class="post-metadata">

**Author:** ![Putzeimer](https://avatars.discourse-cdn.com/v4/letter/p/a9a28c/32.png) [@Putzeimer](https://discourse.nodered.org/u/Putzeimer)\
**Post date:** [6 February 2023 13:36 UTC](https://discourse.nodered.org/t/env-get-is-declared-to-return-a-string-but-in-subflows-it-doesnt/74757/7 "2023-02-06T13:36:02Z")

</div>

I did exactly that. No download is attached to the first post. Simply expand the "Example flow:" section and copy the text.

To clarify the intention of my post: This issue is not about the actual code. There are several workarounds I can use. I just wanted to point out a weird behaviour in node-red that should be examined and fixed, if considered a bug.

---

<div class="post-metadata">

**Author:** ![Colin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/colin/32/17040_2.png) [@Colin](https://discourse.nodered.org/u/Colin)\
**Post date:** [6 February 2023 13:41 UTC](https://discourse.nodered.org/t/env-get-is-declared-to-return-a-string-but-in-subflows-it-doesnt/74757/8 "2023-02-06T13:41:49Z")

</div>

I wonder whether node-red overrides env.get() in subflows in order to support json and other types. In that case presumably the editor has no way of knowing that node-red is overriding it.

@Putzeimer if you try the code in a function outside of a subflow does the editor still complain. It doesn't matter that the code will not run, it is just the syntax checker that we are testing.

**[Edit]** Ignore the last paragraph, of course it will complain, and in that case is right to do so.

---

<div class="post-metadata">

**Author:** ![E1cid](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/e1cid/32/77971_2.png) [@E1cid](https://discourse.nodered.org/u/E1cid)\
**Post date:** [6 February 2023 13:48 UTC](https://discourse.nodered.org/t/env-get-is-declared-to-return-a-string-but-in-subflows-it-doesnt/74757/9 "2023-02-06T13:48:22Z")

</div>

Sorry, saw the example flow and thought it was a download link.

Have you tried declaring List as an array first?  
e.g.

```auto
let List = [];
List = env.get('List');
node.warn(typeof List);
node.warn(Array.isArray(List));
node.warn(List);
for (let i in List)
    node.warn(List[i]);
return msg;

```

---

<div class="post-metadata">

**Author:** ![Putzeimer](https://avatars.discourse-cdn.com/v4/letter/p/a9a28c/32.png) [@Putzeimer](https://discourse.nodered.org/u/Putzeimer)\
**Post date:** [6 February 2023 14:23 UTC](https://discourse.nodered.org/t/env-get-is-declared-to-return-a-string-but-in-subflows-it-doesnt/74757/10 "2023-02-06T14:23:55Z")

</div>

> [@Colin](#):
>
> I wonder whether node-red overrides env.get() in subflows in order to support json and other types. In that case presumably the editor has no way of knowing that node-red is overriding it.

Yes, I guess that is exactly the point. I updated the topic to indicate that it is only subflow related.

Maybe it would be cleaner to use two seperate functions. Something like this:  
`env.get()` to get a _regular_ environment variable of type `string` but **not** subflow environment variables.  
`subflow.get()` to get subflow environment variables of type `any` but **not** _regular_ environment variables.

So in function nodes (no matter if in subflow ot not) you could use:  
`env.get('NR_NODE_NAME');`  
And in function nodes **only** inside a subflow:  
`subflow.get('List');`  
The downside of this change would be the lack of downward compatibility. So perhaps one of the developers comes up with a better idea?

> [@E1cid](#):
>
> Have you tried declaring List as an array first?

Indeed, the editor then interpretes `List` as a string even though it's not. I don't get why that's working. However, this is just another workaround and doesn't address the problem at it's core.

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/d073cd938eafa2e558d7c2cd59003b3ef4963033.png) [@system](https://discourse.nodered.org/u/system)\
**Post date:** [7 April 2023 14:24 UTC](https://discourse.nodered.org/t/env-get-is-declared-to-return-a-string-but-in-subflows-it-doesnt/74757/11 "2023-04-07T14:24:16Z")

</div>

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.
