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

Object.entries and Object.values are not type safe. #44586

Closed
samwightt opened this issue Jun 15, 2021 · 4 comments
Closed

Object.entries and Object.values are not type safe. #44586

samwightt opened this issue Jun 15, 2021 · 4 comments

Comments

@samwightt
Copy link

lib Update Request

Configuration Check

My compilation target is ESNext and my lib is the default.

Missing / Incorrect Definition

The generics on Object.values and Object.entries for the value types are unsafe. They narrow the types for the value when it is unsafe to do so. Because any object is assignable to a given object type only if it contains the expected fields, Object.entries and Object.values might produce unexpected values, resulting in a runtime error that could've been prevented.

The definition for Object.entries is slightly confusing: it contains the valid type for the keys (string | number), which prevents type errors when trying to access properties on the object. However, this is not the case for the value type, which seems inconsistent.

The type safe definition would be to set the value type to unknown: this forces the user to explicitly check the type of the value before accessing it, while also making it clear that the value type is truly unknown. The current typing is likely to have no runtime errors the majority of the time, while an unknown typing ensures there are no type errors.

Sample Code

Example code:

type User = {
  name: string;
  email: string;
}

let userWIthMoreInfo = {
  name: "John Doe",
  email: "[email protected]",
  age: 27
}

let user: User = userWithMoreInfo;

Object.entries(user).forEach([key, value] => {
  const reverse = value.split('').reverse().join(); // throws an error.
})

Documentation Link

None that I'm aware of.

@Paril
Copy link

Paril commented Jun 15, 2021

Same for Object.keys when the object has known keys (ie, Object.keys({ one: 1, two: 2, three: 3 }), you'd expect this to be one | two | three but it's just string[], which makes sense for most contexts but not in this one where it's clear)

@samwightt
Copy link
Author

Same for Object.keys when the object has known keys (ie, Object.keys({ one: 1, two: 2, three: 3 }), you'd expect this to be one | two | three but it's just string[], which makes sense for most contexts but not in this one where it's clear)

This has been covered before. Object.keys is not type safe with a generic. See here for reasoning on this. TLDR: thanks to structural typing and how Typescript does type compatibility, it is possible for objects to have more keys than their types explicitly list. The correct, type-safe behavior with Typescript's type system is to have the result be a string[]. Other implementations that use a generic are not type safe and will have runtime errors.

Object.keys is not within the scope of this issue. I'm specifically talking about making the behavior of Object.values and Object.entries identical to Object.keys: removing the generic, which makes things type safe.

@MartinJohns
Copy link
Contributor

See #38520.

@samwightt
Copy link
Author

Awesome, thanks! Closing this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants