Closed
Description
TypeScript Version: nightly (2.1.0-dev.20160804)
Code
function f(s: Set<string> | Set<number>) {
// (1)
s = new Set<number>();
s // s is Set<number>
if (s instanceof Set) { } // Clearly no side-effects here. No possible changes to s.
s // s is Set<number> | Set<any> <===== (1a)
s.add(42); // ERROR: Cannot invoke an expression whose type lacks call signature <===== (1b)
// (2)
s = new Set<number>();
s // s is Set<number>
if (s instanceof Promise) { } // Clearly no side-effects here. No possible changes to s.
s // s is Set<number> | (Set<number> & Promise<any>) <===== (2a)
s.add(42); // No error this time <===== (2b)
}
function g(s: Set<string> | Set<number>) {
// (3)
s // s is Set<string> | Set<number>
if (s instanceof Set) {
s // s is Set<string> | Set<number>
}
else {
s // s is never <===== (3a)
s.add(42); // ERROR 'add' does not exist on never <===== (3b)
}
// (4)
s = new Set<number>();
s // s is Set<number>
if (s instanceof Set) {
s // s is Set<any>
}
else {
s // s is Set<number> <===== (4a)
s.add(42); // no error, but we couldn't possibly have a Set instance here <===== (4b)
}
}
Expected behavior:
- inferred type of
s
at (1a) isSet<number>
- inferred type of
s
at (2a) isSet<number>
- inferred type of
s
at (3a) isnever
- inferred type of
s
at (4a) isnever
- Compiler errors at (3b) and (4b)
- No compiler errors at (1b) and (2b)
Actual behavior:
- inferred type of
s
at (1a) isSet<number> | Set<any>
- inferred type of
s
at (2a) isSet<number> | (Set<number> & Promise<any>)
- inferred type of
s
at (3a) isnever
- inferred type of
s
at (4a) isSet<number>
- Compiler errors at (1b) and (3b)
- No compiler errors at (2b) and (4b)
Notes:
Brought over from #9862 which is closed. See that issue for the discussion leading to the above examples. Cc: @ahejlsberg, @sandersn