Skip to content

Inconsistent boolean literal typesΒ #48363

Description

πŸ•— Version & Regression Information

This is the behavior in every version I tried.

⏯ Playground Link

Playground link with relevant code

πŸ’» Code

// Box<T> type is invariant in T

type Box<T> = {
    get: () => T,
    set: (value: T) => void
}

declare function box<T>(value: T): Box<T>;

const bn1 = box(0);  // Box<number>
const bn2: Box<number> = box(0);  // Ok

const bb1 = box(false);  // Box<boolean>
const bb2: Box<boolean> = box(false);  // Error, box<false> not assignable to Box<boolean>

πŸ™ Actual behavior

Error on bb2 is surprising and inconsistent with lack of error on bn2.

πŸ™‚ Expected behavior

Expected the box(false) expression to have type Box<boolean> for both bb1 and bb2.

Activity

  1. MartinJohns commented on Mar 21, 2022

    @MartinJohns
    Contributor

    Related: #48150

  2. ahejlsberg commented on Mar 21, 2022

    @ahejlsberg
    MemberAuthor

    The issue here is that when a boolean literal (false or true) is contextually typed by type boolean, we don't widen the type of the literal to boolean. This is inconsistent with our behavior for string, number and bigint literals which are widened when their contextual type is string, number or bigint, respectively. The difference comes from the fact that boolean is just an alias for the union type false | true, whereas string, number, and bigint aren't (infinite) unions of literals, but rather distinct primitive types.

    This issue was discussed in #48150 and before that here. It definitely seems odd and inconsistent. We'd be better off considering the contextual type boolean akin to string, number, and bigint for purposes of widening literals. I know we tried that in the past and one issue was a boolean contextual type arising from separate false and true types as discriminants. For example:

    let x: { kind: false, x: number } | { kind: true, x: string } = { kind: false, x: 42 };

    Here, at least in the past, the kind property in the object literal would have the contextual type boolean (the union of false and true). However, these days we discriminate the contextual type by discriminant properties in the object literal, thus removing the { kind: true, x: string } variant, and therefore the contextual type is just false. And thus we wouldn't widen.

    I'm going to put up a PR to see what the effects are.

  3. locked as resolved and limited conversation to collaborators on Oct 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

BugA bug in TypeScriptFix AvailableA PR has been opened for this issue

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions