Skip to content

Narrowed type information is **sometimes** lost in callback functions.Β #52055

Description

Bug Report

πŸ”Ž Search Terms

type narrowing, callback

πŸ•— Version & Regression Information

This is the behavior in every version I tried, and I reviewed the FAQ for entries about type guards.

⏯ Playground Link

Playground link with relevant code

πŸ’» Code

type Option = { isSome: true, value: unknown } | { isSome: false };

export default (
  foo: Option,
  bar: { baz: Option },
  qux: (arg: unknown) => unknown
) => {
  if (foo.isSome) {
    foo.value;
    qux(foo.value);
    [].map((_) => foo.value);
  }
  if (bar.baz.isSome) {
    bar.baz.value;
    qux(bar.baz.value);
    [].map((_) => bar.baz.value);
  }
};

πŸ™ Actual behavior

The line [].map((_) => bar.baz.value); does not compile, inferring bar.baz to be of type Option. I thought it was narrowed down to { isSome: true, value: unknown } just like the above two lines.

πŸ™‚ Expected behavior

The aforementioned line should compile as I explained in the last section.

The closest documentation to the situation of my problem is this issue template, which says:

narrowings are not respected in callbacks. In other words:

function fn(obj: { name: string | number }) {
  if (typeof obj.name === "string") {
    // Errors
    window.setTimeout(() => console.log(obj.name.toLowerCase());
  }
}

This is intentional since the value of obj.name "could" change types between when the narrowing occurred and when the callback was invoke [sic].

This might make sense, but does not seem to explain why [].map((_) => foo.value); compiles. I don't see why foo.value and bar.baz.value in callbacks produce different results, so I opened this issue.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions