Error solution: Uncaught TypeError Uncaught TypeError: document.getElementById(...) is null
I have a single JavaScript file that is connected to multiple pages. The below snippet is a function that is used for a single page. The above error appears when the user navigates to one of the pages that does not use the below function, and it references the document.getElementById('button01').addEventListener('click', newThing); line at the bottom. I've gathered that the error comes up due to the fact that button01 does not exist on these pages.
function newThing() {
const output = document.getElementsByTagName('output')[0];
if (!(document.forms.thingSelection2.type.value in options)) {
    return false;
}
const list = options[document.forms.thingSelection2.type.value];
const method = document.forms.thingSelection1.mode.value + 'Item';
const item = list[method]();
output.innerHTML = item;

}
document.getElementById('button01').addEventListener('click', newThing);

Solution
My solution for this is simple; place the line in an if statement like so:
if(document.getElementById('button01')) {
    document.getElementById('button01').addEventListener('click', newThing);
}

This removes the error from the pages that don't use it.
Questions
Does this open up the possibility for any buggy behavior that I don't know about? Is there a better way to achieve the same results?
HTML
I'm thankful for the feedback this post has received thus far. Since some of the answers contain recommendations based on assumptions of my HTML, I've decided to add the respective HTML in the below snippet. One thing to note is that I use two forms. This is required for the functionality of the code. I'm unaware of any unintended bugs this may cause. If it does, please let me know below.
&lt;div&gt;&lt;output&gt;&lt;/output&gt;&lt;/div&gt;
&lt;div&gt;&lt;button id=&quot;button01&quot;&gt;New Thing&lt;/button&gt;&lt;/div&gt;
&lt;div&gt;
   &lt;form name=&quot;thingSelection1&quot;&gt;
      &lt;input type=&quot;radio&quot; name=&quot;mode&quot; value=&quot;random&quot; id=&quot;mode1&quot;&gt;&amp;nbsp;Random
      &lt;br/&gt;&lt;input type=&quot;radio&quot; name=&quot;mode&quot; value=&quot;forward&quot; id=&quot;mode2&quot;&gt;&amp;nbsp;Old&amp;nbsp;-&amp;nbsp;New
      &lt;br/&gt;&lt;input type=&quot;radio&quot; name=&quot;mode&quot; value=&quot;reverse&quot; id=&quot;mode3&quot;&gt;&amp;nbsp;New&amp;nbsp;-&amp;nbsp;Old
   &lt;/form&gt;
&lt;/div&gt;
&lt;div&gt;
   &lt;form name=&quot;thingSelection2&quot;&gt;
       Doodle&amp;nbsp;&lt;input type=&quot;radio&quot; name=&quot;type&quot; value=&quot;doodle&quot; id=&quot;doodleCheck&quot;&gt;&lt;br/&gt;
       Video&amp;nbsp;&lt;input type=&quot;radio&quot; name=&quot;type&quot; value=&quot;video&quot; id=&quot;videoCheck&quot;&gt;&lt;br/&gt;
       Audio&amp;nbsp;&lt;input type=&quot;radio&quot; name=&quot;type&quot; value=&quot;audio&quot; id=&quot;audioCheck&quot;&gt;&lt;br/&gt;
       Photo&amp;nbsp;&lt;input type=&quot;radio&quot; name=&quot;type&quot; value=&quot;photo&quot; id=&quot;photoCheck&quot;&gt;&lt;br/&gt;
       Text&amp;nbsp;&lt;input type=&quot;radio&quot; name=&quot;type&quot; value=&quot;text&quot; id=&quot;textCheck&quot;&gt;
   &lt;/form&gt;
 &lt;/div&gt;

Furthermore, I'd like to point out that the original snippet is only part of my full JavaScript. Based on the information provided by this post, I've concluded that adding the remaining JavaScript, while possibly beneficial and relevant to some of the answers below, could possibly be out of the scope of the original topic of this post. Please note your thoughts on this in the comments below.
Does this open up the possibility for any buggy behavior that I don't know about?

It's not likely to. The if statement is fine, though it can be made cleaner:

Rather than selecting the element twice (once to check to see if it exists, another time to call addEventListener on it), save it in a variable:
const button = document.getElementById('button01');
if (button) {
  button.addEventListener('click', newThing);
}


Or, if you're writing JS which gets transpiled for production (which, in a professional or larger project, you really should be), use optional chaining:
document.getElementById('button01')?.addEventListener('click', newThing);



But the fundamental issue remains - the HTML layout is completely disconnected from the JavaScript. Having to check to see if a button exists in the first place is something that ideally shouldn't be an issue to worry about, at least in a larger or more professional project. What if you had not 1, but 3 or 5 or 10 elements with handlers on different pages, all of which may or may not exist? The codebase would be more difficult to maintain than it should be.
There are a few solutions for this:

One option is to have a separate &lt;script&gt; file for pages with the form, eg:

&lt;form id=&quot;thingSelection2&quot;&gt;
...
&lt;/form&gt;
&lt;script src=&quot;./thingSelection.js&quot;&gt;&lt;/script&gt;

where thingSelection.js adds the event listener. But that'll require a separate request to the server, which may be a problem on a large page on HTTP 1.1 - if you have lots of different scripts like this, the sheer number of parallel requests could slow things down, especially for users with high latency. (The HTTP/2 protocol doesn't have issues with additional connections to the same server IIRC)
(You could also inline the script, eg &lt;/form&gt;&lt;script&gt;// etc&lt;/script&gt;but I prefer putting scripts in separate files to permit caching)

But if it were me, I'd strongly prefer to fully integrate the creation of the HTML with the event listeners for that HTML, to make it completely inconceivable of one existing without the other, using a framework. For example, with React, you could do something along the lines of:

const Things = () =&gt; {
    const [item, setItem] = useState('');
    const [selectedOption, setSelectedOption] = useState('foo');
    const clickHandler = (e) =&gt; {
        const fn = options[selectedOption];
        if (fn) {
          setItem(fn());
        }
    };
    return (
        &lt;div&gt;
            &lt;select value={selectedOption} onChange={e =&gt; setSelectedOption(e.currentTarget.value)}&gt;
                &lt;option value=&quot;foo&quot;&gt;foo&lt;/option&gt;
                &lt;option value=&quot;bar&quot;&gt;bar&lt;/option&gt;
            &lt;/select&gt;
            &lt;button onClick={clickHandler}&gt;click&lt;/button&gt;
            &lt;output&gt;{item}&lt;/output&gt;
        &lt;/div&gt;
    );
};



const options = {
  foo: () =&gt; 'foo',
  bar: () =&gt; 'bar',
};

const Things = () =&gt; {
    const [item, setItem] = React.useState('');
    const [selectedOption, setSelectedOption] = React.useState('foo');
    const clickHandler = (e) =&gt; {
        const fn = options[selectedOption];
        if (fn) {
          setItem(fn());
        }
    };
    return (
        &lt;div&gt;
            &lt;select value={selectedOption} onChange={e =&gt; setSelectedOption(e.currentTarget.value)}&gt;
                &lt;option value="foo"&gt;foo&lt;/option&gt;
                &lt;option value="bar"&gt;bar&lt;/option&gt;
            &lt;/select&gt;
            &lt;button onClick={clickHandler}&gt;click&lt;/button&gt;
            &lt;output&gt;{item}&lt;/output&gt;
        &lt;/div&gt;
    );
};
ReactDOM.render(&lt;Things /&gt;, document.querySelector('.react'));
&lt;script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"&gt;&lt;/script&gt;
&lt;script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"&gt;&lt;/script&gt;
&lt;div class="react"&gt;&lt;/div&gt;



Then when you're on a page where the Things are needed, you just render &lt;Things /&gt;. With this approach, the HTML its associated JS handlers are all completely self-contained in the Things. There's no need to use selectors that may have unintentional collisions. (For example, going with your original code of document.getElementById('button01'), what if some other completely separate section of the HTML on one of the pages had an element which accidentally used the same ID? Then you'll have problems.)
Using a framework like this is admittedly a lot to learn, but it makes codebases significantly more maintainable. It's well worth it for medium-size or larger projects, IMO.

On a different note, your current code could also be improved a bit:
Prefer selectors Selector strings are usually more easily understood and more flexible than other methods of selecting elements (like getElementsByTagName and document.forms.someFormName.someFormElement). The selector string that matches an element will line up with the CSS selector that styles the element. For example, I'd replace:
document.forms.thingSelection2.type.value

with
document.querySelector('#thingSelection2 [name=type]').value

and
const output = document.getElementsByTagName('output')[0];

with
const output = document.querySelector('output');

(no need to select a collection when you only need the single matching element)
Save the value Instead of selecting and extracting the value twice, write DRY code; put it into a variable:
const { value } = document.querySelector('#thingSelection2 [name=type]');
if (value in options) { // Or, use `!options[value]
  return false;
}