Promise-based fixed delay poller with timeout
Polling is not good.

I'm curious if there is a more idiomatic or flexible way for this to be written.

Generally polling for a state change is not considered best practice so there is no idiomatic approch.
The code

async functions are a promise you don't need to put them inside a promise, you are just doubling up.


 const fixedDelayPoller = new Promise(async () =&gt; {
     while (!predicate()) {
         await promiseTimeout(delayMS); 
     }
 });


Then the same as with one less promise to negotiate.
 const fixedDelayPoller = (async () =&gt; {
     while (!predicate()) {
         await promiseTimeout(delayMS); 
      }
 })(); // invoke async function


It seams that JS coders are still getting used to promises as they never name the callbacks. You name the callback resolve but that is inferred and does not describe what the function does


  return new Promise((resolve) =&gt; {
    return setTimeout(resolve, ms);
  });


would be better as
  return new Promise(timeup =&gt; setTimeout(timeup, ms))


You are creating way too many promises. When you look at the problem you only need one promise that resolves on timeout or predicate() is true. As your code stands you create 5 promises (Promise.race counts as a promise) minimum and then an extra one for each delay timeout.
A better approch is to have the poll function return only one promise. You can then resolve it without the need to create a string of promises one after another.


function poll(predicate, delayMS, timeoutMS){
    var intervalHandle;
    return new Promise(pollingOver =&gt; {
        const complete = () =&gt; {
            clearInterval(intervalHandle);
            pollingOver();
        }
        intervalHandle = setInterval(() =&gt; predicate() &amp;&amp; complete(), delayMS);
        setTimeout(complete, timeoutMS);
    });
}



function poll(predicate, delayMS, timeoutMS){
    var intervalHandle;
    return new Promise(pollingOver =&gt; {
        const complete = (ready = false) =&gt; {
            clearInterval(intervalHandle);
            pollingOver(ready);
        }
        intervalHandle = setInterval(() =&gt; predicate() &amp;&amp; complete(true), delayMS);
        setTimeout(complete, timeoutMS);
    });
}


// Poll waits fot state to === true or two seconds
test();
var state;
function test() {
    state = false;
    var timer = setTimeout(()=&gt;state = true, Math.random() * 4000)
    poll(() =&gt; state, 200, 2000).then(inTime =&gt; {
        console.log(inTime ? "State in time" : "State change timed out");
        clearTimeout(timer);
        test();
    });
}



Back to your questions

I'm curious if there is a more idiomatic or flexible way for this to be written. For example, should there be parameters for a callback to be called after the timeout? Or would that be handled by the caller calling poll(x, y, z).then(onFulfilled)? Further, should this function return a boolean rather than a possible void, false in the case of timeout and true otherwise?

If you did need some event to happen on resolution then using poll(...).then( is the better approch.
Should your function return a bool? that is up to you. The predicate has access to the state so it can be used to workout the current state. However it is better to return a result via the promise callback (see snippet above, returns false on timeout)
Why are you polling?
I am having trouble understanding why you need to poll some state. There are many other ways to communicate state changes in JavaScript (TypeScript) without the need for code to run at regular intervals. But without some context it is hard to say which approch would be best.