Skip to content

Control Flow Analysis for Destructured Discriminated Unions doesn't work for let variablesΒ #48071

Open
@kasperpeulen

Description

@kasperpeulen

Bug Report

πŸ”Ž Search Terms

Control flow analysis destructuring assignment

πŸ•— Version & Regression Information

This was already there, but I thought it might have been fixed with the introduction of this feature in 4.6.

⏯ Playground Link

Playground link with relevant code

πŸ’» Code

export const reduce = <S, T extends S>(self: Iterable<T>, operation: (acc: S, t: T) => S): S => {
  const iter = self[Symbol.iterator]();
  let { value, done }: IteratorResult<T, unknown> = iter.next();
  if (done) throw new Error("Empty iterable can't be reduced.");
  let acc: S = value; // Type 'unknown' is not assignable to type 'S'.
  while (!done) {
    acc = operation(acc, value);
    ({ value, done } = iter.next());
  }
  return acc;
};

Note that if you don't upcast iter.next(), you won't get errors, but not for good reasons:

let {value, done} = iter.next(); // type is IteratorResult<T, any>
if (done) throw new Error("Empty iterable can't be reduced.");
// value is any and can be assigned to anything

A smaller repo would be:

export function foo(iter: Iterator<number, string>) {
  let { value, done } = iter.next();
  if (done) return;
  let acc: number = value; // Type 'string | number' is not assignable to type 'number'. Type 'string' is not assignable to type 'number'.
  return acc;
}

πŸ™ Actual behavior

value above in the last example is inferred as number | string, it should be number

πŸ™‚ Expected behavior

I expect the same inference as without destructuring:

export const reduce2 = <S, T extends S>(self: Iterable<T>, operation: (acc: S, t: T) => S): S => {
  const iter = self[Symbol.iterator]();
  let result: IteratorResult<T, unknown> = iter.next();
  if (result.done) throw new Error("Empty iterable can't be reduced.");
  let acc: S = result.value; // result.value is T (extends S)
  while (!result.done) {
    acc = operation(acc, result.value);
    result = iter.next();
  }
  return acc;
};

Metadata

Metadata

Assignees

No one assigned

    Labels

    Needs InvestigationThis issue needs a team member to investigate its status.

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions