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;
};
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
Note that if you don't upcast
iter.next(), you won't get errors, but not for good reasons:A smaller repo would be:
π Actual behavior
valueabove in the last example is inferred asnumber | string, it should benumberπ Expected behavior
I expect the same inference as without destructuring: