Doesn't excuse the JS ecosystem and JS as a whole, which truly is a mess. But there's a history behind these things.
If your API works with promises, call .then() on what is handed to you. That's it. Don't make up emergent, untestable behavior on the spot.
ISTM that a framework may need to test for promiseness if it calls promises and functions differently, but it can and should be done as a utility in the framework, not as a separate package.
It’s possible to just treat everything as a promise by wrapping results in Promise.resolve() but that can have performance implications that some franeworks might want to avoid by only going down the promise route when they have to.
For promise implementations, If the callback to then() returns a promise, the promise implementation detects that and resolves that promise behind the scenes: http://www.mattgreer.org/articles/promises-in-wicked-detail/...
In properly designed languages, values have either a known concrete type, or the interfaces that they have to support are listed, and the compiler checks them.
Even in JavaScript/TypeScript, if you are using this, you or a library you are using are doing it wrong, since you should know whether a value is a promise or not when writing code.