Skip to content

Rethinking relationships between {} type, object, and primitivesΒ #60582

Open
@kirkwaiblinger

Description

@kirkwaiblinger

πŸ”Ž Search Terms

empty object type, {}, type safety violation, unsound

πŸ•— Version & Regression Information

⏯ Playground Link

https://www.typescriptlang.org/play/?ts=5.8.0-dev.20241124#code/GYVwdgxgLglg9mABFAhgawKYGcDyAjAKw2gAoAPALkTkOKgEpEBvAKEXcQHpPEAVACxhZEAJxgBzflAA2AT0RDEKPgGVEGESLgiAdGw4xgicogC85xAAZGrDncQQEWONIw6NWkSQDkAxXhEUSH5ELH44EGkAE0Q8DERwEQwUCH4UPFdvegBufXYAXxZClkcwLChqKiZ8sytclm5EACEQCqhBYSEwbygAGiUwGLCI6Ni3FlRMXFpSOBygA

πŸ’» Code

function takesObject(x: object) {
    // This rightly is a TS error.
    if (x === 0) {
        console.error('This branch should be unreachable');
    }
}

const o: {} = 0;

// But this isn't, and should be.
takesObject(o);

πŸ™ Actual behavior

No error on takesObject(o). {} can be assigned to type object, despite {} meaning "all nonnullish values", whereas object means only JS object types.

πŸ™‚ Expected behavior

Error on takesObject(o). {} is a wider type than object.

Additional information about the issue

This stems from a typescript-eslint investigation into making no-unnecessary-condition be more correct around possibly-falsy "object types", such as {}, or even { toFixed(): string} (to which number may be assigned). See typescript-eslint/typescript-eslint#10378. This also relates to previous (controversial) conversations about whether to flag the {} type with the linter, see, e.g. typescript-eslint/typescript-eslint#8700.

I'm wondering if this was simply an oversight in #49119, which aimed to fix soundness holes with {}?

Metadata

Metadata

Assignees

No one assigned

    Labels

    Needs ProposalThis issue needs a plan that clarifies the finer details of how it could be implemented.SuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions