I propose we add a never function, that's defined somewhat like this:
globalThis.AssertionError = class extends Error {}
globalThis.never = function(message = 'The program found itself in a bad state') {
throw new AssertionError(message)
}
It's purpose it to help self-document when certain things should never happen, and to provide assertions to make sure they really don't happen.
Yes, it's easy for userland to define a function like this, but placing this within JavaScript makes it part of the common language that we can all read and understand instantly. never()
looses a lot of it's self-documentation power if the code reader has to look up it's definition to figure out what it does.
Motivating examples
// Throw an error if a particular type isn't handled
messageEvent.addListener(({ type, payload }) => {
if (type === 'UNDO') {
// ...
} else if (type === 'REDO') {
// ...
} else never()
})
// Show that certain code paths should never execute
function getPlayer() {
for (const entity of entities) {
if (entity.type === 'PLAYER') return entity
}
never()
}
// Self-document that you expect something to always be found in the array
// (so you're not left wondering if `player` could be undefined)
const player = entities.find(e => e.type === 'PLAYER') ?? never()
// Assertions
function helperFunction() {
if (!isInit) never()
// ...
}
// Show that a function will never return
function runGameLoop() {
while (true) {
await new Promise(resolve => resolve(), 100)
// ...
}
never()
}
Prior art
This is very loosely inspired by Elm's never() function. Elm's never() was intended to help the type-system ensure that specific code paths never execute, while the never() I'm proposing here does a runtime-check instead.
Related resources
Error.assert() thread - Love this idea - too bad it hasn't seen much attention yet.
throw as exception proposal