As a concept, standard I/O is decoupled from terminals and devices. However, it can be useful to know whether a program is directly connected to a terminal or whether its I/O is being redirected.
We can check with the isTTY flag on each I/O channel.
For instance, let's try the following command:
$ node -p "process.stdin.isTTY"
true
The -p flag will evaluate a supplied string and output the final result. There's also the related -e flag which only evaluates a supplied command line string, but doesn't output its return value.
We're running node directly, so our STDIN is correctly identified as a TTY input.
Now let's try the following:
$ echo "hi" | node -p "process.stdin.isTTY"
undefined
This time isTTY is undefined. This is because our program is executed inside a shell pipeline. It's important to note that isTTY is undefined and not false, as this can lead to bugs (for instance, when checking for a false value instead of a falsey result).
The isTTY flag is undefined instead of false in the second case because the standard I/O channels are internally initialized from different constructors depending on the scenario. So when the process is directly connected to a terminal, process.stdin is created using the core tty module's ReadStream constructor, which has the isTTY flag. However, when I/O is redirected, the channels are created from the net module's Socket constructor, which does not have an isTTY flag.
Knowing whether a process is directly connected to a terminal can be useful in certain cases – for instance, when determining whether to output plain text or text decorated with ANSI escape codes for coloring, boldness, and so forth.