-
Notifications
You must be signed in to change notification settings - Fork 12.8k
[fix] ES5 Object.keys only accepts an object #27089
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Heya @ljharb! Looks like our baselines might need to be updated - it's likely the symbol baselines are printing out a different type for uses of Additionally, is there a reason why |
@DanielRosenwasser yes, because the spec for Object.keys changed in ES2015 to no longer throw on non-nullish primitives (numbers, strings, booleans, symbols) - so while a type of Thanks, I'll update the tests shortly. |
7a74838
to
7e89a05
Compare
Tests updated. |
Is there an associated bug for this? |
@RyanCavanaugh no, i didn't file one - it seemed like this would be faster. If you need me to file one that copy-pastes the first two lines in the OP, i can certainly do that. |
ping - does this really need an issue, or is it ready to go as-is? |
7e89a05
to
8b95922
Compare
@DanielRosenwasser @RyanCavanaugh any update? |
47fd1d4
to
e830f52
Compare
hm, test failures seem unrelated |
@RyanCavanaugh yay, how soon is "soon"? :-D |
e830f52
to
bc43904
Compare
@RyanCavanaugh any update? |
bc43904
to
0b0ca1e
Compare
@ljharb the reason we ask for an associated issue is that the issue is how we track whether or not we decide we want a PR for something in the first place. I think it's a broadly open question whether calling e.g. |
@RyanCavanaugh sure, that's fine; there's no harm in closing the PR if you don't decide you want the change. However, I'd argue it's not about "sensical" - it's allowed by the spec, and it was explicitly changed in ES6 because people pass primitives into The primary issue is that the ES5 types are incorrect - they currently allow passing non-object non-nullish primitives, but ES5 disallowed this, and only ES2015 enabled that. |
We've had this discussion on Twitter already 😉 I think this is fine to merge once the failing tests gets fixed. |
a08fb56
to
b3c7a62
Compare
Tests should now be fixed. |
After a longer discussion than expected on the merits of |
I opened this because it’s a bug, because i do it this way on purpose in qs, a very well-used library. I’m disappointed in this outcome. |
@RyanCavanaugh it’s also worth noting - what’s in master does not agree with your decision, because you have the ES5 types as the empty interface. The correction is to make es5 object and es6+ the empty interface. In other words, what you want is what I’m asking for es5 to do, and what you don’t want is what typescript already does. |
I think that when this was discussed at the backlog slog, we misunderstood the topic. I'm sorry about that. The root of the problem is that any sort of change sort of needs to build up its worth, especially when there's some risk of breakage or new conceptual overhead. Regardless of the eventual change, creating the distinction between ES5/ES2015 seems like it would be confusing (i.e. having an overload for You already saw the opposite approach - we erroneously assumed the type already was |
My intention here was for those targeting es5 to be able to get warning of a runtime exception before it happens. Without this PR, the type system will allow it, but an ES5 runtime will not. |
@ljharb This is what I see in the PR and what we were basing our discussion off of: I don't see any part of the PR that adds an |
I'm OK taking the PR in its intended form 😉 |
a7eed53
to
9867d8a
Compare
Thanks, sorry for all the back-and-forth. PR updated. |
@ljharb looks like you need to run |
9867d8a
to
f1bcc80
Compare
@RyanCavanaugh oops, thanks. Done! |
This broke VS Code |
@RyanCavanaugh can you elaborate? #31380 (comment) implies it caught a bug in vscode, not broke it. |
@RyanCavanaugh ah, gotcha. that suggests a bug in type narrowing then :-) thanks for the followup. |
Let's say you have code like this declare function keys(obj: object): string[];
function fn<T extends null | object>(arg: T) {
// Point 1
if (!arg) return;
// Point 2
if (typeof arg !== "object") return;
// Point 3
keys(arg);
} There's an error here because To get the "correct" answer for the type of We'd need #22348 or its equivalent to track this. |
That seems excessively valuable given that truthiness and falsiness are both core and idiomatic mechanisms used for runtime guards. Hopefully that could land soon, and type narrowing improved? |
It's not that we don't recognize the value of it, believe me 😉 |
ES5 Object.keys throws on non-objects: http://www.ecma-international.org/ecma-262/5.1/#sec-15.2.3.14 - which is type
object
.ES2015 Object.keys allows any "object coercible", ie any non-null non-undefined value - which is
{}
: http://www.ecma-international.org/ecma-262/6.0/#sec-object.keysThis attempts to fix the types.
'Bug' or 'help wanted' or is in the Community milestone
master
branchjake runtests
locallyThis is my first PR to TypeScript; if you can point me to where I should add unit tests, I'll be happy to do so.