Beginning with Vuex 3.4.0, actions always return a native promise. In past versions, Vuex only checked whether an action returned a thennable object, i.e. anything with .then property. If not, it wrapped the action return value in a new promise. But if so, it simply returned the object without wrapping it, assuming it was a promise. Starting with 3.4.0, Vuex wraps even thennable objects.
So in the past, the $.Deferred promise was able to slip by, because it has a .then method which returns a $ promise object with a .fail method. But now it gets wrapped in a native promise.
registerAction
If you inspect the Vuex source, you see that registerAction didn't change from 3.3.0 to 3.4.0. This is where non-thennable return values are wrapped in promises. It hasn't changed:
function registerAction (store, type, handler, local) {
...
if (!isPromise(res)) {
res = Promise.resolve(res);
}
...
}
store.dispatch.prototype
But store.dispatch.prototype did change. It used to just return the .then method:
return result.then(function (res) {
...
})
But now it always returns a promise wrapper:
return new Promise(function (resolve, reject) {
result.then(function (res) { // Doesn't return the inner promise either
...
})
})
And the wrapper doesn't bother to return the inner result either. It seems Vuex has decided to normalize the return value of actions so that it's guaranteed to be a native promise.