Skip to content

Inconsistent type widening with results of higher-order functions #51551

Closed as not planned

Description

Bug Report

When assigning the value 0 or 1 to the field of an object, see below, type widening infers the type number. When doing the same through a generic higher-order function, the field gets the type 0 | 1. This can trigger a type error when using that value in another generic high-order function that assigns to the object as a side-effect.

🔎 Search Terms

type widening
inconsistency

🕗 Version & Regression Information

Appears in all versions on Playground (back to 3.3.3333).

Also appears in Nightly (v. 5.0.0.-dev20221116)

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about widening

⏯ Playground Link

Playground link with relevant code

💻 Code

// The following example works by type widening

function wrap<L>(v: L): { val: L } {
    return { val: v };
}

export function thisworks(): number {
    const g = (b: boolean) => { return b ? 1 : 0; }
    let o = wrap(g(true));
    o   /// Type: o: { val: number }
    o.val += 1;
    // o.val : number
    return o.val;
}

// The following example does exactly the same but combines `wrap` and `g`
// into a single call to a high-order function.
// Now type-widening doesn't apply.

function applyWrap<L>(b: boolean, map: (b: boolean) => L): { val: L } {
    return { val: map(b) };
}

function mapVal<L>(o: { val: L }, map: (arg: L) => L): void {
    o.val = map(o.val);
}

export function doesntwork(): { val: number } {
    let o = applyWrap(true, (b: boolean) => { return b ? 1 : 0; });
    o   /// Type: o: { val: 0 | 1 }
    // The next line triggers an error by again preventing type widening in the assignment
    mapVal(o, v => { return v + 1; });
    // This line would have worked:
    // o.val += 1
    return o;
}

🙁 Actual behavior

I get a type error in the function doesntwork on the mapVal call. This is because type widening did not apply as expected to o, so it has type { val: 0 | 1 }. Simultaneously, type widening is also disabled at the mutation mapVal -- simply writing o.val += 1 instead of the mapVal call would have worked.

🙂 Expected behavior

I expected that the behaviour of type widening remains the same in the case of using high-order callbacks to generate the value and not.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    Not a DefectThis behavior is one of several equally-correct options

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions