Skip to content

Object.entries/values incorrectly narrowsΒ #62691

@SnowSquire

Description

@SnowSquire

πŸ”Ž Search Terms

Object.entries Object.values

πŸ•— Version & Regression Information

This has existed since Typescript 3.9.7, which is when definitions for Object.entries/values were added.

⏯ Playground Link

https://www.typescriptlang.org/play/?ts=6.0.0-dev.20251029#code/MYewdgzgLgBAsgTwPICMBWMC8MDeAoGGAUwA8AHI4KIgEwGsiEAuGAIgAsBLVvAXxgCGEGKEhQ8eKAgrxk6ACrSiWGFIogAZrNRoJGgK5gqncDCRgANgkQ6AFCHQsbCpQEp8hAPSeYANwEWMJzCnAC2ZABOIBQRVrYA-PGuMGACEVEA7rQwNCAZYKogbFw8hBogETC2otAwANoMCAA0fgEAujCaZuiUUAB0RGBQEZxEEPboru4EhCLgECAWRH0WIADmto0t-hauM7wz5ZXV87A7nVo6vX07+mMTaFMeszWLy6sbO3uEBwd4BkYoCYCtRoLZks8arBQhVlNhnoRSBQqLRGiwONwmjNCIYkb1UYx0SgQCBSjB+EI5mI8ABIcxWZxoWyM75mSzWORMmERIh7Gl8SRjKDgoA

πŸ’» Code

const MyObj = {
  expectedkey: "hi"
} as const

type MyObjType = typeof MyObj

function OnlyMyObj(obj: MyObjType){
  // val is improperly(??) narrowed down to "hi"
  for (const [key, val] of Object.entries(obj)){
    console.log(key, val)
  }
  for (const val of Object.values(obj)){
    console.log(val)
  }
}

function test() {
  const more = {
    expectedkey: "hi",
    unexpectedkey: "boo"
  } as const
	OnlyMyObj(MyObj)
  OnlyMyObj(more)
	
}
test()

πŸ™ Actual behavior

The type for val in OnlyMyObj() is incorrectly narrowed to "hi" when it's entirely possible to get other values if there are unexpected keys.

πŸ™‚ Expected behavior

Since the key from Object.entries/keys is currently not narrowed to account for cases of there being extraneous keys, I believe the proper type for val would be unknown.

Additional information about the issue

Typescript already catches a very similar error and has the error at the call site which would be preferable to changing the return type of entries/values. Not sure if that can be done though.

https://www.typescriptlang.org/play/?ts=6.0.0-dev.20251029#code/MYewdgzgLgBAsgTwPICMBWMC8MDeAoGGAUwA8AHI4KIgEwGsiEAuGAIgAsBLVvAXxgCGEGKEhQ8eKAgrxk6ACrSiWGFIogAZrNRoJeDQFcwVTuBhIwAGwSIdAChDoWAJUogATjQA80d5zAA5gA0HNwAfACU+IQA9DEwAG4CljCcwpwAtmTuIBTu1nYA-IURMGAC7jkA7rQwNCBVYKogbFw8hBoeMHai0DAA2gwIQYnJALowmubolFAAdERgUH5EEA7oEVEEhCLgECCWRHOWIAF2QyNJlhHbvNud7t29sFeTWjqzc1cGq+tom9Edr0DkcTmcrjdCHc7vojCYzNRoHZSoDnjAMh5lNhAYRSBQqLQhixQqwgttCEY8bNCYwWABOW6CYTPPAASAs1ls6DsXP+2w5NjkaDsGPcRBurL4klWUGRQA

const MyObj = {
  expectedkey: "hi"
} as const

type MyObjType = typeof MyObj


function OnlyMyObj(obj: Record<string,"hi">){
  // val is improperly(??) narrowed down to "hi"
  for (const [key, val] of Object.entries(obj)){
    console.log(key, val)
  }
  for (const val of Object.values(obj)){
    console.log(val)
  }
}

function test() {
  const more = {
    expectedkey: "hi",
    unexpectedkey: 9
  } as const
	OnlyMyObj(MyObj)
  OnlyMyObj(more)
	
}
test()

Metadata

Metadata

Assignees

No one assigned

    Labels

    DuplicateAn existing issue was already created

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions