Error handling is up to the author. If you don't control some code that throws, and you want it to not throw, wrap it with something that catches but doesn't throw. In your own code, you should feel free to return error objects rather than throw.
Just be aware that others have come to expect throw/catch as a convention.
// this one throws errors
import fnNotControlledByMe from 'external_lib'
// use this one as a wrapper, and don't throw
// this and any other function you write can opt not to throw
async function fnControlledByMe() {
try {
let results = fnNotControlledByMe();
return results;
} catch (err) {
return { err };
}
}
async function opFunction() {
let results = await fnControlledByMe();
results?.err ? doSomething() : handleErr()
}