Darien Valentine (2018-07-20T11:29:34.000Z)
valentinium at gmail.com (2018-07-20T11:31:24.106Z)
In `Promise.prototype.then`: > 1. Let promise be the this value. > 2. If IsPromise(promise) is false, throw a TypeError exception. > [ ... ] In `Promise.prototype.finally`: > 1. Let promise be the this value. > 2. If Type(promise) is not Object, throw a TypeError exception. > [...] In `Promise.prototype.catch`: > 1. Let promise be the this value. > 2. Return ? Invoke(promise, "then", « undefined, onRejected »). First, this means that only `then` requires the this value to be a Promise: ```js for (const key of [ 'then', 'finally', 'catch' ]) { try { Promise.prototype[key].call({ then: () => console.log(`${ key } doesn’t brand check its this value`) }); } catch (err) { console.log(`${ key } does brand check its this value`); } } // > then does brand check its this value // > finally doesn’t brand check its this value // > catch doesn’t brand check its this value ``` Second, note that `Invoke` uses `GetV`, not `Get`. Thus: ```js for (const key of [ 'then', 'finally', 'catch' ]) { try { String.prototype.then = () => console.log(`${ key } casts this value to object`); Promise.prototype[key].call('foo'); } catch (err) { console.log(`${ key } doesn’t cast this value to object`); } } // > then doesn’t cast this value to object // > finally doesn’t cast this value to object // > catch casts this value to object ``` On reflection, I think I see the logic to this: - `Promise.prototype.then` ends up executing `PerformPromiseThen`, which requires its first argument to be a native promise object. - `Promise.prototype.finally` ends up executing `SpeciesConstructor`, which requires its first argument to be an object. - `Promise.prototype.catch` does neither. However the inconsistency within this trio seems pretty odd to me. I suppose I would have expected them all to be as constrained as the most constrained method needed to be for the sake of uniformity, given that they constitute a single API. Conversely, if the goal was for each method to be exactly as lenient as is possible, then `finally` seems to be over-constrained; it seems like `C` could have just defaulted to `Promise` in cases where `SpeciesConstructor` wasn’t applicable, making it as lenient as `catch`. I wasn’t able to find prior discussion about this, though it’s a bit hard to search for, so I may be missing it. Do these behaviors seem odd to anyone else, or is it what you’d expect?