You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Unnecessary any returned from Object.values and Object.entries #58376
This is a duplicate of #26010 which I believe can now be fixed. Object.entries and Object.values can now return the correct types without impacting enums.
Why would Object.values(i) return I[]? None of the properties are Is. The point Martin is making is that TS is only seeing the types here and there's no guarantee that a thing typed as I only has string | null values.
typeholes Just to be clear: From the type checker's point of view there's no difference between the explicitly typed o in your example and the explicitly typed i in Martin's. Returning (string | null)[] when Object.values is called on an I wouldn't be sound.
Supporting arrays makes sense. I'm guessing the string index signature is meant for object-as-a-dictionary scenarios. Either one has a potential hazard with excess properties, though.
Correct, so my question is should we be inconsistent between the interface and record values. I think consistency would be better, especially when you consider that any is just explicitly unsound.
It's not really inconsistent though. Index signatures and interfaces represent different things.
Index signatures are "arrayish." They may not necessarily have numeric keys, but they represent collections of key/value pairs where the "element" values all conform to a single type, so it makes sense for Object.values to support this scenario.
By its very nature, an interface is not exhaustive. An interface represents a subset of an object's actual shape (or a commonality among otherwise differently-shaped objects). So even if Object.values returned a union of known property types based on the interface, you would still have to include unknown in the union to account for properties not identified by the interface. And if you include unknown in the union, then the entire thing reduces to unknown.
That it returns any instead of unknown is unfortunate, but it's due to historical reasons.
Activity
MartinJohns commentedon Apr 30, 2024
This is working as intended.
This is perfectly legal code, and a return type of
(string | null)[]would be wrong:nmain commentedon Apr 30, 2024
See this FAQ entry: https://github.com/microsoft/TypeScript/wiki/FAQ#indirect-excess-properties-are-ok
typeholes commentedon Apr 30, 2024
Scratch that, I see the issue and it should really be returning
unknown[]I understand how that FAQ applies to
Object.keys, but I do not think it applies here.Here you have explicitly type
i: Iso I would expect thatObject.valueswould returnI[string|number][](edit: per fatCerebus's correction)note that if you let
ibe inferred the result would be(string | number | null)[]which is also correctfatcerberus commentedon Apr 30, 2024
Why would
Object.values(i)returnI[]? None of the properties areIs. The point Martin is making is that TS is only seeing the types here and there's no guarantee that a thing typed asIonly hasstring | nullvalues.MartinJohns commentedon Apr 30, 2024
Agreed, but that would be a very big breaking change for little gain.
That was intentional to demonstrate the point. You don't know where and how the object was created.
fatcerberus commentedon Apr 30, 2024
typeholes Just to be clear: From the type checker's point of view there's no difference between the explicitly typed
oin your example and the explicitly typediin Martin's. Returning(string | null)[]whenObject.valuesis called on anIwouldn't be sound.typeholes commentedon Apr 30, 2024
Interestingly we have the exact same issue with a record, but do get the specific result type
https://www.typescriptlang.org/play/?target=99&jsx=0&exactOptionalPropertyTypes=true&lib=lib.esnext.d.ts&ts=5.5.0-dev.20240429#code/PTAEAEBcEMCcHMCmkBcpEGcB2iAekAoECAGwEsAjNTHfAgsrSRWAM2gGNFQBJUAb1ABtXGiwBXALYUWAXTQZIsRvFAAfUBJIlQAblABfUPUgBPAA7cAKqAC8oAEqIOAe1gATADwTpLADSgispY8GpaJAB89K5YiqAudgKgrC4uaACMAEwAzAEArGgA5MyKhQEAHGLi2oa6BDFxLlZoNvYu+g2Q8QBuraAA8hQAVs6QAHTd0CTimAAUTQCU+qDEs0Eq6prVJAtCskRgoEfHJ6enAHoA-PUusV0uPGh8bR23jd3PA8OjE1MzGPMeEsjsRoFhTHsDmdoTCrvQCEA
snarbies commentedon Apr 30, 2024
Object.values has an overload for array-likes and string index signatures (but not bare numeric index signatures).
Supporting arrays makes sense. I'm guessing the string index signature is meant for object-as-a-dictionary scenarios. Either one has a potential hazard with excess properties, though.
typeholes commentedon Apr 30, 2024
Correct, so my question is should we be inconsistent between the interface and record values. I think consistency would be better, especially when you consider that
anyis just explicitly unsound.snarbies commentedon May 2, 2024
It's not really inconsistent though. Index signatures and interfaces represent different things.
Index signatures are "arrayish." They may not necessarily have numeric keys, but they represent collections of key/value pairs where the "element" values all conform to a single type, so it makes sense for
Object.valuesto support this scenario.By its very nature, an interface is not exhaustive. An interface represents a subset of an object's actual shape (or a commonality among otherwise differently-shaped objects). So even if
Object.valuesreturned a union of known property types based on the interface, you would still have to includeunknownin the union to account for properties not identified by the interface. And if you includeunknownin the union, then the entire thing reduces tounknown.That it returns
anyinstead ofunknownis unfortunate, but it's due to historical reasons.typeholes commentedon May 3, 2024
Implementation is in #58358
typescript-bot commentedon May 6, 2024
This issue has been marked as "Question" and has seen no recent activity. It has been automatically closed for house-keeping purposes.