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 behaves differently for interfaces and types #49872

Closed
phryneas opened this issue Jul 12, 2022 · 6 comments
Closed

Object.entries behaves differently for interfaces and types #49872

phryneas opened this issue Jul 12, 2022 · 6 comments
Labels
Not a Defect This behavior is one of several equally-correct options

Comments

@phryneas
Copy link

Bug Report

When using types, Object.entries returns a union of possible values as value, while a similar interface, it returns any

🔎 Search Terms

Object.entries union any

🕗 Version & Regression Information

This seems to go back at least until TS 4, I didn't test further.

⏯ Playground Link

Playground link with relevant code

💻 Code

// explicit type has union as value type
{
    type Foo = {
        key: "value",
        anotherKey: number
    }

    let x: Foo = { key: "value", anotherKey: 3 }

    //const entries: [string, number | "value"][]
    const entries = Object.entries(x)
}

// explicit interface has `any` as value type
{
    interface Foo {
        key: "value",
        anotherKey: number
    }

    let x: Foo = { key: "value", anotherKey: 3 }

    //const entries: [string, any][]
    const entries = Object.entries(x)
}

🙁 Actual behavior

Object.entries behaves differently for types and interfaces

🙂 Expected behavior

Object.entries behaves the same for types and interfaces.

I am aware that the general argument is "interfaces could be extended" - but pretty much the same goes for a type here as well, right?
Is this an oversight or intended behaviour?

@MartinJohns
Copy link
Contributor

MartinJohns commented Jul 12, 2022

I am aware that the general argument is "interfaces could be extended" - but pretty much the same goes for a type here as well, right?

Interfaces are subject to declaration merging, whereas type aliases are not.

See also #38520. Object.entries() should really always return any or unknown.

@Josh-Cena
Copy link
Contributor

Object.entries() should really always return any or unknown.

You mean [string, any][]?

@phryneas
Copy link
Author

phryneas commented Jul 12, 2022

@MartinJohns yeah, but the basic logic that applies for both is equally (un)sound.
Breaking this is easily possible with both an interface and a type (playground), so it is very unintuitive that they would behave so differently.

Tbh., I'd be fine with either behaviour (although personally I prefer the "unsound, but usable" behaviour over any and would argue that if it's the any behaviour, it should be unknown instead) - but having a difference between a type and an interface here just adds more confusion on top.

@Josh-Cena
Copy link
Contributor

The issue is still because interfaces don't have implicit string index signatures, causing it to fail to match the entries<T>(o: { [s: string]: T } | ArrayLike<T>): [string, T][]; overload. Last time it was brought up at #49751

@phryneas
Copy link
Author

Ah, that's at least a puzzle piece that explains it.

@RyanCavanaugh RyanCavanaugh added the Not a Defect This behavior is one of several equally-correct options label Jul 12, 2022
@github-actions
Copy link

github-actions bot commented Jun 8, 2023

This issue has been marked as 'Not a Defect' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

@github-actions github-actions bot closed this as not planned Won't fix, can't repro, duplicate, stale Jun 8, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Not a Defect This behavior is one of several equally-correct options
Projects
None yet
Development

No branches or pull requests

4 participants