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
Add an overload to Object.fromEntries when called with const tuples #50379
Object.fromEntries as is declared today results in a loss of key names and a unionization of all values, or a complete loss of information and type of any.
This change would make it so that it is possible to create strict objects — from const tuples only.
Note that the usage of fromEntries with Arrays and non-readonly tuples cannot be made sound, so this issue only discusses the narrow case of const tuples.
Sample Code
constobj1=Object.fromEntries([['1',2],['3',4],]asconst)// this should result in an object of type: {1: 2, 3: 4}, but results instead in: { [k: string]: 2 | 4 }constobj2=Object.fromEntries([['1',2],['3','4'],]asconst)// should result in an object of type: {1: 2, 3: '4'}, but results in: any
The how & example
This could be achieved by adding a new overload to Object.fromEntries in the case it is called with const tuples only.
This distinction is vital, because not distinguishing between Arrays, tuples and const tuples would make this change unsound. Only properties of a readonly tuple are guaranteed to be there at runtime, since they cannot be reassigned.
The type is somewhat complex right now, so it would be great if we could somehow simplify it. Suggestions are welcome.
Related issues were previously closed, because the change would have been unsound without guarding for const tuples only (#35745, #49305, #43332). Here however, the discussion is around const tuples only.
Configuration Check
My compilation target is es2022 and my lib is es2022.
I really would rather avoid a conditional return type, at least not as the last overload. By supporting a reduced, but still improved, set of features I think this is better:
// Most generally usefuldeclarefunctionfromEntries<Textendsreadonly[PropertyKey,unknown]>(entries: Iterable<T>): {[PinTasP[0]]?: P[1]}// Support wonky union types like `[["foo", 1]] | Iterable<["bar", 2]>`declarefunctionfromEntries<KextendsPropertyKey,V>(entries: Iterable<readonly[K,V]>): {[_inK]?: V}// For people destructuring `fromEntries`declarefunctionfromEntries(entries: Iterable<readonly[PropertyKey,unknown]>): {[key: PropertyKey]: unknown}
I just noticed that this breaks the obj2_fromMixed case
This is extremely clever, but far too complex to put into the standard library. Since this can merge in at the top of the overload list, you can still get the same behavior in userland with a custom additional lib file.
Ryan Cavanaugh (@RyanCavanaugh) thanks for taking a look. I can make an NPM library for that, sounds like the way to go, unfortunately.
It would be possible to make this much simpler, if we had these two things built-in in TypeScript:
When doing a mapped type, ability to conditionally set optionality.
Right now, one can set the value using the X extends Y ? ... : ... pattern, but one cannot do it to add in or remove ? conditionally.
Perhaps a special type like +? or -? to add or remove optionality in mapped types, and similarly to add or remove readonly property +readonly could be added? E.g. { [K in keyof O]: O[K] extends X ? X & +? : X & -? }
Ability to refine based on negation. E.g. only const tuples: T extends readonly [...unknown] & not [...unknown]
webstrand the failing test case you mentioned is failing for a good reason - there's no way to create a predictable object from that type, so it should be handled by another overload and fallback to a less strictly typed type. And as you notice, your simplified version unfortunately isn't sound. Believe me I've spent hours trying to figure it out.
Activity
webstrand commentedon Aug 24, 2022
Another failing test case
webstrand commentedon Aug 24, 2022
I really would rather avoid a conditional return type, at least not as the last overload. By supporting a reduced, but still improved, set of features I think this is better:
I just noticed that this breaks the
obj2_fromMixedcaseRyanCavanaugh commentedon Aug 25, 2022
This is extremely clever, but far too complex to put into the standard library. Since this can merge in at the top of the overload list, you can still get the same behavior in userland with a custom additional lib file.
niieani commentedon Aug 26, 2022
Ryan Cavanaugh (@RyanCavanaugh) thanks for taking a look. I can make an NPM library for that, sounds like the way to go, unfortunately.
It would be possible to make this much simpler, if we had these two things built-in in TypeScript:
Right now, one can set the value using the
X extends Y ? ... : ...pattern, but one cannot do it to add in or remove?conditionally.Perhaps a special type like
+?or-?to add or remove optionality in mapped types, and similarly to add or remove readonly property+readonlycould be added? E.g.{ [K in keyof O]: O[K] extends X ? X & +? : X & -? }T extends readonly [...unknown] & not [...unknown]webstrand the failing test case you mentioned is failing for a good reason - there's no way to create a predictable object from that type, so it should be handled by another overload and fallback to a less strictly typed type. And as you notice, your simplified version unfortunately isn't sound. Believe me I've spent hours trying to figure it out.
alexweej commentedon Nov 21, 2022
Yes, please!
niieani commentedon Feb 8, 2023
I've finally gotten around to publishing an NPM package with the strict Object.fromEntries typings.
See nesity-types.
sandersn commentedon Feb 8, 2023
Would it be OK to close this PR now?