Skip to content
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

Add stricter Object.fromEntries for constructing from const tuples #50203

Closed
wants to merge 4 commits into from

Conversation

niieani
Copy link

@niieani niieani commented Aug 6, 2022

Related issue: #50379.

UPDATE: The version in this branch is unsound, but see the last comment here with a proposed solution that is sound.


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 makes it so that it is possible to create strict objects from const tuples.

const obj1 = Object.fromEntries([
  ['1', 2],
  ['3', 4],
] as const)

// now results in an object of type: {1: 2, 3: 4}, previously { [k: string]: 2 | 4 }

const obj2 = Object.fromEntries([
  ['1', 2],
  ['3', '4'],
] as const)

// now results in an object of type: {1: 2, 3: '4'}, previously any

Fixes #35745, #49305, #43332

`Object.fromEntries` as is declared today resulted in a loss of key names and a unionization of all values, or a complete loss of information and type of `any`. 
This change makes it so that it is possible to create strict objects from const tuples.

```ts
const obj1 = Object.fromEntries([
  ['1', 2],
  ['3', 4],
] as const)

// now results in an object of type: {1: 2, 3: 4}, previously { [k: string]: 2 | 4 }

const obj2 = Object.fromEntries([
  ['1', 2],
  ['3', '4'],
] as const)

// now results in an object of type: {1: 2, 3: '4'}, previously any
```
@typescript-bot
Copy link
Collaborator

It looks like you've sent a pull request to update our 'lib' files. These files aren't meant to be edited by hand, as they consist of last-known good states of the compiler and are generated from 'src/lib' or possibly our lib generator. Unless this is necessary, consider closing the pull request and sending a separate PR to update 'src/lib' or https://github.com/microsoft/TypeScript-DOM-lib-generator

@typescript-bot typescript-bot added lib update PR modifies files in the `lib` folder For Uncommitted Bug PR for untriaged, rejected, closed or missing bug labels Aug 6, 2022
@typescript-bot
Copy link
Collaborator

The TypeScript team hasn't accepted the linked issue #35745. If you can get it accepted, this PR will have a better chance of being reviewed.

@Josh-Cena
Copy link
Contributor

Josh-Cena commented Aug 6, 2022

@niieani
Copy link
Author

niieani commented Aug 6, 2022

@Josh-Cena that's unfortunate. Is there any way to only target const tuples in the type system, without affecting mutable Arrays?

EDIT: ooh, what if I did check for extends Array<any> ? never : ... ?

@Josh-Cena
Copy link
Contributor

No, you can only target fixed length tuples—for example, add ten overloads for [[K, V]], [[K, V], [K, V]], etc. But there's not type to represent "any fixed-length tuple"

@sandersn sandersn added this to Not started in PR Backlog Aug 17, 2022
@sandersn
Copy link
Member

Given that the design is still in flux, I'd recommend opening a new issue to continue discussion. Then this PR should be either a draft or closed.

@sandersn sandersn moved this from Not started to Waiting on author in PR Backlog Aug 17, 2022
Only create strict types from const tuples, since we cannot guarantee the existence of any key in an iterable.
@niieani
Copy link
Author

niieani commented Aug 18, 2022

@sandersn @Josh-Cena I've addressed the issue. Here's a playground showing that it works correctly in all cases.
With the updated typings, only objects created from const tuples will have their shape known, as those are guaranteed to be present and thus sound.

Non-const tuples and regular arrays fallback to the old (currently released) behavior, i.e. they're either a Record if values are of the same type, or any.

@sandersn
Copy link
Member

Can you still open an issue to track this? All the issues you reference are closed, which makes me think that they're missing something new about what you've done. In particular, I'd like to see @RyanCavanaugh 's opinion about your last comment on #35745 .

@niieani
Copy link
Author

niieani commented Aug 19, 2022

@sandersn I can create an issue. I've discovered an unsoundness in my last implementation.
Let me see if I can fix it first, and I'll get back to you and ping Ryan.

@niieani
Copy link
Author

niieani commented Aug 20, 2022

Okay, I've solved the soundness issue, but it turned out to be a bit complex.

Here's the playground.

@sandersn @RyanCavanaugh Perhaps there's an easier way to type this? Would anyone have suggestions on how to simplify this?

I'll hold off on updating the PR with the sound solution, until I get a green light.

EDIT: Opened #50379.

@niieani
Copy link
Author

niieani commented Feb 8, 2023

Just FYI for anyone following, I've finally gotten around to publishing an NPM package with the strict Object.fromEntries typings. It doesn't suffer from any unsoundness as far as I can tell and is fully compatible with the regular Object.fromEntries.
See nesity-types.

@niieani niieani closed this Feb 14, 2023
PR Backlog automation moved this from Waiting on author to Done Feb 14, 2023
@niieani niieani deleted the patch-1 branch February 14, 2023 17:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
For Uncommitted Bug PR for untriaged, rejected, closed or missing bug lib update PR modifies files in the `lib` folder
Projects
PR Backlog
  
Done
Development

Successfully merging this pull request may close these issues.

Support known possible keys in Object.entries and Object.fromEntries
5 participants