Merge pull request #10194 from Microsoft/fixInstanceofNarrowing
Fix instanceof narrowing
This commit is contained in:
commit
8ea90ab28b
|
@ -8126,6 +8126,25 @@ namespace ts {
|
|||
return source.flags & TypeFlags.Union ? !forEach((<UnionType>source).types, t => !contains(types, t)) : contains(types, source);
|
||||
}
|
||||
|
||||
function isTypeSubsetOf(source: Type, target: Type) {
|
||||
return source === target || target.flags & TypeFlags.Union && isTypeSubsetOfUnion(source, <UnionType>target);
|
||||
}
|
||||
|
||||
function isTypeSubsetOfUnion(source: Type, target: UnionType) {
|
||||
if (source.flags & TypeFlags.Union) {
|
||||
for (const t of (<UnionType>source).types) {
|
||||
if (!containsType(target.types, t)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (source.flags & TypeFlags.EnumLiteral && target.flags & TypeFlags.Enum && (<EnumLiteralType>source).baseType === target) {
|
||||
return true;
|
||||
}
|
||||
return containsType(target.types, source);
|
||||
}
|
||||
|
||||
function filterType(type: Type, f: (t: Type) => boolean): Type {
|
||||
return type.flags & TypeFlags.Union ?
|
||||
getUnionType(filter((<UnionType>type).types, f)) :
|
||||
|
@ -8272,6 +8291,7 @@ namespace ts {
|
|||
|
||||
function getTypeAtFlowBranchLabel(flow: FlowLabel): FlowType {
|
||||
const antecedentTypes: Type[] = [];
|
||||
let subtypeReduction = false;
|
||||
let seenIncomplete = false;
|
||||
for (const antecedent of flow.antecedents) {
|
||||
const flowType = getTypeAtFlowNode(antecedent);
|
||||
|
@ -8286,11 +8306,17 @@ namespace ts {
|
|||
if (!contains(antecedentTypes, type)) {
|
||||
antecedentTypes.push(type);
|
||||
}
|
||||
// If an antecedent type is not a subset of the declared type, we need to perform
|
||||
// subtype reduction. This happens when a "foreign" type is injected into the control
|
||||
// flow using the instanceof operator or a user defined type predicate.
|
||||
if (!isTypeSubsetOf(type, declaredType)) {
|
||||
subtypeReduction = true;
|
||||
}
|
||||
if (isIncomplete(flowType)) {
|
||||
seenIncomplete = true;
|
||||
}
|
||||
}
|
||||
return createFlowType(getUnionType(antecedentTypes), seenIncomplete);
|
||||
return createFlowType(getUnionType(antecedentTypes, subtypeReduction), seenIncomplete);
|
||||
}
|
||||
|
||||
function getTypeAtFlowLoopLabel(flow: FlowLabel): FlowType {
|
||||
|
@ -8316,6 +8342,7 @@ namespace ts {
|
|||
// Add the flow loop junction and reference to the in-process stack and analyze
|
||||
// each antecedent code path.
|
||||
const antecedentTypes: Type[] = [];
|
||||
let subtypeReduction = false;
|
||||
flowLoopNodes[flowLoopCount] = flow;
|
||||
flowLoopKeys[flowLoopCount] = key;
|
||||
flowLoopTypes[flowLoopCount] = antecedentTypes;
|
||||
|
@ -8332,6 +8359,12 @@ namespace ts {
|
|||
if (!contains(antecedentTypes, type)) {
|
||||
antecedentTypes.push(type);
|
||||
}
|
||||
// If an antecedent type is not a subset of the declared type, we need to perform
|
||||
// subtype reduction. This happens when a "foreign" type is injected into the control
|
||||
// flow using the instanceof operator or a user defined type predicate.
|
||||
if (!isTypeSubsetOf(type, declaredType)) {
|
||||
subtypeReduction = true;
|
||||
}
|
||||
// If the type at a particular antecedent path is the declared type there is no
|
||||
// reason to process more antecedents since the only possible outcome is subtypes
|
||||
// that will be removed in the final union type anyway.
|
||||
|
@ -8339,7 +8372,7 @@ namespace ts {
|
|||
break;
|
||||
}
|
||||
}
|
||||
return cache[key] = getUnionType(antecedentTypes);
|
||||
return cache[key] = getUnionType(antecedentTypes, subtypeReduction);
|
||||
}
|
||||
|
||||
function isMatchingReferenceDiscriminant(expr: Expression) {
|
||||
|
@ -8537,9 +8570,7 @@ namespace ts {
|
|||
|
||||
function getNarrowedType(type: Type, candidate: Type, assumeTrue: boolean) {
|
||||
if (!assumeTrue) {
|
||||
return type.flags & TypeFlags.Union ?
|
||||
getUnionType(filter((<UnionType>type).types, t => !isTypeSubtypeOf(t, candidate))) :
|
||||
type;
|
||||
return filterType(type, t => !isTypeSubtypeOf(t, candidate));
|
||||
}
|
||||
// If the current type is a union type, remove all constituents that aren't assignable to
|
||||
// the candidate type. If one or more constituents remain, return a union of those.
|
||||
|
@ -8549,13 +8580,16 @@ namespace ts {
|
|||
return getUnionType(assignableConstituents);
|
||||
}
|
||||
}
|
||||
// If the candidate type is assignable to the target type, narrow to the candidate type.
|
||||
// Otherwise, if the current type is assignable to the candidate, keep the current type.
|
||||
// Otherwise, the types are completely unrelated, so narrow to the empty type.
|
||||
// If the candidate type is a subtype of the target type, narrow to the candidate type.
|
||||
// Otherwise, if the target type is assignable to the candidate type, keep the target type.
|
||||
// Otherwise, if the candidate type is assignable to the target type, narrow to the candidate
|
||||
// type. Otherwise, the types are completely unrelated, so narrow to an intersection of the
|
||||
// two types.
|
||||
const targetType = type.flags & TypeFlags.TypeParameter ? getApparentType(type) : type;
|
||||
return isTypeAssignableTo(candidate, targetType) ? candidate :
|
||||
return isTypeSubtypeOf(candidate, targetType) ? candidate :
|
||||
isTypeAssignableTo(type, candidate) ? type :
|
||||
getIntersectionType([type, candidate]);
|
||||
isTypeAssignableTo(candidate, targetType) ? candidate :
|
||||
getIntersectionType([type, candidate]);
|
||||
}
|
||||
|
||||
function narrowTypeByTypePredicate(type: Type, callExpression: CallExpression, assumeTrue: boolean): Type {
|
||||
|
|
|
@ -86,8 +86,8 @@ if (isNodeList(sourceObj) || isHTMLCollection(sourceObj)) {
|
|||
>sourceObj : Symbol(sourceObj, Decl(controlFlowBinaryOrExpression.ts, 23, 3))
|
||||
|
||||
sourceObj.length;
|
||||
>sourceObj.length : Symbol(length, Decl(controlFlowBinaryOrExpression.ts, 10, 27), Decl(controlFlowBinaryOrExpression.ts, 14, 33))
|
||||
>sourceObj.length : Symbol(NodeList.length, Decl(controlFlowBinaryOrExpression.ts, 10, 27))
|
||||
>sourceObj : Symbol(sourceObj, Decl(controlFlowBinaryOrExpression.ts, 23, 3))
|
||||
>length : Symbol(length, Decl(controlFlowBinaryOrExpression.ts, 10, 27), Decl(controlFlowBinaryOrExpression.ts, 14, 33))
|
||||
>length : Symbol(NodeList.length, Decl(controlFlowBinaryOrExpression.ts, 10, 27))
|
||||
}
|
||||
|
||||
|
|
|
@ -106,7 +106,7 @@ if (isNodeList(sourceObj) || isHTMLCollection(sourceObj)) {
|
|||
|
||||
sourceObj.length;
|
||||
>sourceObj.length : number
|
||||
>sourceObj : NodeList | HTMLCollection | ({ a: string; } & HTMLCollection)
|
||||
>sourceObj : NodeList
|
||||
>length : number
|
||||
}
|
||||
|
||||
|
|
184
tests/baselines/reference/controlFlowInstanceof.js
Normal file
184
tests/baselines/reference/controlFlowInstanceof.js
Normal file
|
@ -0,0 +1,184 @@
|
|||
//// [controlFlowInstanceof.ts]
|
||||
|
||||
// Repros from #10167
|
||||
|
||||
function f1(s: Set<string> | Set<number>) {
|
||||
s = new Set<number>();
|
||||
s; // Set<number>
|
||||
if (s instanceof Set) {
|
||||
s; // Set<number>
|
||||
}
|
||||
s; // Set<number>
|
||||
s.add(42);
|
||||
}
|
||||
|
||||
function f2(s: Set<string> | Set<number>) {
|
||||
s = new Set<number>();
|
||||
s; // Set<number>
|
||||
if (s instanceof Promise) {
|
||||
s; // Set<number> & Promise<any>
|
||||
}
|
||||
s; // Set<number>
|
||||
s.add(42);
|
||||
}
|
||||
|
||||
function f3(s: Set<string> | Set<number>) {
|
||||
s; // Set<string> | Set<number>
|
||||
if (s instanceof Set) {
|
||||
s; // Set<string> | Set<number>
|
||||
}
|
||||
else {
|
||||
s; // never
|
||||
}
|
||||
}
|
||||
|
||||
function f4(s: Set<string> | Set<number>) {
|
||||
s = new Set<number>();
|
||||
s; // Set<number>
|
||||
if (s instanceof Set) {
|
||||
s; // Set<number>
|
||||
}
|
||||
else {
|
||||
s; // never
|
||||
}
|
||||
}
|
||||
|
||||
// More tests
|
||||
|
||||
class A { a: string }
|
||||
class B extends A { b: string }
|
||||
class C extends A { c: string }
|
||||
|
||||
function foo(x: A | undefined) {
|
||||
x; // A | undefined
|
||||
if (x instanceof B || x instanceof C) {
|
||||
x; // B | C
|
||||
}
|
||||
x; // A | undefined
|
||||
if (x instanceof B && x instanceof C) {
|
||||
x; // B & C
|
||||
}
|
||||
x; // A | undefined
|
||||
if (!x) {
|
||||
return;
|
||||
}
|
||||
x; // A
|
||||
if (x instanceof B) {
|
||||
x; // B
|
||||
if (x instanceof C) {
|
||||
x; // B & C
|
||||
}
|
||||
else {
|
||||
x; // B
|
||||
}
|
||||
x; // B
|
||||
}
|
||||
else {
|
||||
x; // A
|
||||
}
|
||||
x; // A
|
||||
}
|
||||
|
||||
// X is neither assignable to Y nor a subtype of Y
|
||||
// Y is assignable to X, but not a subtype of X
|
||||
|
||||
interface X {
|
||||
x?: string;
|
||||
}
|
||||
|
||||
class Y {
|
||||
y: string;
|
||||
}
|
||||
|
||||
function goo(x: X) {
|
||||
x;
|
||||
if (x instanceof Y) {
|
||||
x.y;
|
||||
}
|
||||
x;
|
||||
}
|
||||
|
||||
//// [controlFlowInstanceof.js]
|
||||
// Repros from #10167
|
||||
function f1(s) {
|
||||
s = new Set();
|
||||
s; // Set<number>
|
||||
if (s instanceof Set) {
|
||||
s; // Set<number>
|
||||
}
|
||||
s; // Set<number>
|
||||
s.add(42);
|
||||
}
|
||||
function f2(s) {
|
||||
s = new Set();
|
||||
s; // Set<number>
|
||||
if (s instanceof Promise) {
|
||||
s; // Set<number> & Promise<any>
|
||||
}
|
||||
s; // Set<number>
|
||||
s.add(42);
|
||||
}
|
||||
function f3(s) {
|
||||
s; // Set<string> | Set<number>
|
||||
if (s instanceof Set) {
|
||||
s; // Set<string> | Set<number>
|
||||
}
|
||||
else {
|
||||
s; // never
|
||||
}
|
||||
}
|
||||
function f4(s) {
|
||||
s = new Set();
|
||||
s; // Set<number>
|
||||
if (s instanceof Set) {
|
||||
s; // Set<number>
|
||||
}
|
||||
else {
|
||||
s; // never
|
||||
}
|
||||
}
|
||||
// More tests
|
||||
class A {
|
||||
}
|
||||
class B extends A {
|
||||
}
|
||||
class C extends A {
|
||||
}
|
||||
function foo(x) {
|
||||
x; // A | undefined
|
||||
if (x instanceof B || x instanceof C) {
|
||||
x; // B | C
|
||||
}
|
||||
x; // A | undefined
|
||||
if (x instanceof B && x instanceof C) {
|
||||
x; // B & C
|
||||
}
|
||||
x; // A | undefined
|
||||
if (!x) {
|
||||
return;
|
||||
}
|
||||
x; // A
|
||||
if (x instanceof B) {
|
||||
x; // B
|
||||
if (x instanceof C) {
|
||||
x; // B & C
|
||||
}
|
||||
else {
|
||||
x; // B
|
||||
}
|
||||
x; // B
|
||||
}
|
||||
else {
|
||||
x; // A
|
||||
}
|
||||
x; // A
|
||||
}
|
||||
class Y {
|
||||
}
|
||||
function goo(x) {
|
||||
x;
|
||||
if (x instanceof Y) {
|
||||
x.y;
|
||||
}
|
||||
x;
|
||||
}
|
232
tests/baselines/reference/controlFlowInstanceof.symbols
Normal file
232
tests/baselines/reference/controlFlowInstanceof.symbols
Normal file
|
@ -0,0 +1,232 @@
|
|||
=== tests/cases/compiler/controlFlowInstanceof.ts ===
|
||||
|
||||
// Repros from #10167
|
||||
|
||||
function f1(s: Set<string> | Set<number>) {
|
||||
>f1 : Symbol(f1, Decl(controlFlowInstanceof.ts, 0, 0))
|
||||
>s : Symbol(s, Decl(controlFlowInstanceof.ts, 3, 12))
|
||||
>Set : Symbol(Set, Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --))
|
||||
>Set : Symbol(Set, Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --))
|
||||
|
||||
s = new Set<number>();
|
||||
>s : Symbol(s, Decl(controlFlowInstanceof.ts, 3, 12))
|
||||
>Set : Symbol(Set, Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --))
|
||||
|
||||
s; // Set<number>
|
||||
>s : Symbol(s, Decl(controlFlowInstanceof.ts, 3, 12))
|
||||
|
||||
if (s instanceof Set) {
|
||||
>s : Symbol(s, Decl(controlFlowInstanceof.ts, 3, 12))
|
||||
>Set : Symbol(Set, Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --))
|
||||
|
||||
s; // Set<number>
|
||||
>s : Symbol(s, Decl(controlFlowInstanceof.ts, 3, 12))
|
||||
}
|
||||
s; // Set<number>
|
||||
>s : Symbol(s, Decl(controlFlowInstanceof.ts, 3, 12))
|
||||
|
||||
s.add(42);
|
||||
>s.add : Symbol(Set.add, Decl(lib.es2015.collection.d.ts, --, --))
|
||||
>s : Symbol(s, Decl(controlFlowInstanceof.ts, 3, 12))
|
||||
>add : Symbol(Set.add, Decl(lib.es2015.collection.d.ts, --, --))
|
||||
}
|
||||
|
||||
function f2(s: Set<string> | Set<number>) {
|
||||
>f2 : Symbol(f2, Decl(controlFlowInstanceof.ts, 11, 1))
|
||||
>s : Symbol(s, Decl(controlFlowInstanceof.ts, 13, 12))
|
||||
>Set : Symbol(Set, Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --))
|
||||
>Set : Symbol(Set, Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --))
|
||||
|
||||
s = new Set<number>();
|
||||
>s : Symbol(s, Decl(controlFlowInstanceof.ts, 13, 12))
|
||||
>Set : Symbol(Set, Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --))
|
||||
|
||||
s; // Set<number>
|
||||
>s : Symbol(s, Decl(controlFlowInstanceof.ts, 13, 12))
|
||||
|
||||
if (s instanceof Promise) {
|
||||
>s : Symbol(s, Decl(controlFlowInstanceof.ts, 13, 12))
|
||||
>Promise : Symbol(Promise, Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --))
|
||||
|
||||
s; // Set<number> & Promise<any>
|
||||
>s : Symbol(s, Decl(controlFlowInstanceof.ts, 13, 12))
|
||||
}
|
||||
s; // Set<number>
|
||||
>s : Symbol(s, Decl(controlFlowInstanceof.ts, 13, 12))
|
||||
|
||||
s.add(42);
|
||||
>s.add : Symbol(Set.add, Decl(lib.es2015.collection.d.ts, --, --))
|
||||
>s : Symbol(s, Decl(controlFlowInstanceof.ts, 13, 12))
|
||||
>add : Symbol(Set.add, Decl(lib.es2015.collection.d.ts, --, --))
|
||||
}
|
||||
|
||||
function f3(s: Set<string> | Set<number>) {
|
||||
>f3 : Symbol(f3, Decl(controlFlowInstanceof.ts, 21, 1))
|
||||
>s : Symbol(s, Decl(controlFlowInstanceof.ts, 23, 12))
|
||||
>Set : Symbol(Set, Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --))
|
||||
>Set : Symbol(Set, Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --))
|
||||
|
||||
s; // Set<string> | Set<number>
|
||||
>s : Symbol(s, Decl(controlFlowInstanceof.ts, 23, 12))
|
||||
|
||||
if (s instanceof Set) {
|
||||
>s : Symbol(s, Decl(controlFlowInstanceof.ts, 23, 12))
|
||||
>Set : Symbol(Set, Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --))
|
||||
|
||||
s; // Set<string> | Set<number>
|
||||
>s : Symbol(s, Decl(controlFlowInstanceof.ts, 23, 12))
|
||||
}
|
||||
else {
|
||||
s; // never
|
||||
>s : Symbol(s, Decl(controlFlowInstanceof.ts, 23, 12))
|
||||
}
|
||||
}
|
||||
|
||||
function f4(s: Set<string> | Set<number>) {
|
||||
>f4 : Symbol(f4, Decl(controlFlowInstanceof.ts, 31, 1))
|
||||
>s : Symbol(s, Decl(controlFlowInstanceof.ts, 33, 12))
|
||||
>Set : Symbol(Set, Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --))
|
||||
>Set : Symbol(Set, Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --))
|
||||
|
||||
s = new Set<number>();
|
||||
>s : Symbol(s, Decl(controlFlowInstanceof.ts, 33, 12))
|
||||
>Set : Symbol(Set, Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --))
|
||||
|
||||
s; // Set<number>
|
||||
>s : Symbol(s, Decl(controlFlowInstanceof.ts, 33, 12))
|
||||
|
||||
if (s instanceof Set) {
|
||||
>s : Symbol(s, Decl(controlFlowInstanceof.ts, 33, 12))
|
||||
>Set : Symbol(Set, Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --))
|
||||
|
||||
s; // Set<number>
|
||||
>s : Symbol(s, Decl(controlFlowInstanceof.ts, 33, 12))
|
||||
}
|
||||
else {
|
||||
s; // never
|
||||
>s : Symbol(s, Decl(controlFlowInstanceof.ts, 33, 12))
|
||||
}
|
||||
}
|
||||
|
||||
// More tests
|
||||
|
||||
class A { a: string }
|
||||
>A : Symbol(A, Decl(controlFlowInstanceof.ts, 42, 1))
|
||||
>a : Symbol(A.a, Decl(controlFlowInstanceof.ts, 46, 9))
|
||||
|
||||
class B extends A { b: string }
|
||||
>B : Symbol(B, Decl(controlFlowInstanceof.ts, 46, 21))
|
||||
>A : Symbol(A, Decl(controlFlowInstanceof.ts, 42, 1))
|
||||
>b : Symbol(B.b, Decl(controlFlowInstanceof.ts, 47, 19))
|
||||
|
||||
class C extends A { c: string }
|
||||
>C : Symbol(C, Decl(controlFlowInstanceof.ts, 47, 31))
|
||||
>A : Symbol(A, Decl(controlFlowInstanceof.ts, 42, 1))
|
||||
>c : Symbol(C.c, Decl(controlFlowInstanceof.ts, 48, 19))
|
||||
|
||||
function foo(x: A | undefined) {
|
||||
>foo : Symbol(foo, Decl(controlFlowInstanceof.ts, 48, 31))
|
||||
>x : Symbol(x, Decl(controlFlowInstanceof.ts, 50, 13))
|
||||
>A : Symbol(A, Decl(controlFlowInstanceof.ts, 42, 1))
|
||||
|
||||
x; // A | undefined
|
||||
>x : Symbol(x, Decl(controlFlowInstanceof.ts, 50, 13))
|
||||
|
||||
if (x instanceof B || x instanceof C) {
|
||||
>x : Symbol(x, Decl(controlFlowInstanceof.ts, 50, 13))
|
||||
>B : Symbol(B, Decl(controlFlowInstanceof.ts, 46, 21))
|
||||
>x : Symbol(x, Decl(controlFlowInstanceof.ts, 50, 13))
|
||||
>C : Symbol(C, Decl(controlFlowInstanceof.ts, 47, 31))
|
||||
|
||||
x; // B | C
|
||||
>x : Symbol(x, Decl(controlFlowInstanceof.ts, 50, 13))
|
||||
}
|
||||
x; // A | undefined
|
||||
>x : Symbol(x, Decl(controlFlowInstanceof.ts, 50, 13))
|
||||
|
||||
if (x instanceof B && x instanceof C) {
|
||||
>x : Symbol(x, Decl(controlFlowInstanceof.ts, 50, 13))
|
||||
>B : Symbol(B, Decl(controlFlowInstanceof.ts, 46, 21))
|
||||
>x : Symbol(x, Decl(controlFlowInstanceof.ts, 50, 13))
|
||||
>C : Symbol(C, Decl(controlFlowInstanceof.ts, 47, 31))
|
||||
|
||||
x; // B & C
|
||||
>x : Symbol(x, Decl(controlFlowInstanceof.ts, 50, 13))
|
||||
}
|
||||
x; // A | undefined
|
||||
>x : Symbol(x, Decl(controlFlowInstanceof.ts, 50, 13))
|
||||
|
||||
if (!x) {
|
||||
>x : Symbol(x, Decl(controlFlowInstanceof.ts, 50, 13))
|
||||
|
||||
return;
|
||||
}
|
||||
x; // A
|
||||
>x : Symbol(x, Decl(controlFlowInstanceof.ts, 50, 13))
|
||||
|
||||
if (x instanceof B) {
|
||||
>x : Symbol(x, Decl(controlFlowInstanceof.ts, 50, 13))
|
||||
>B : Symbol(B, Decl(controlFlowInstanceof.ts, 46, 21))
|
||||
|
||||
x; // B
|
||||
>x : Symbol(x, Decl(controlFlowInstanceof.ts, 50, 13))
|
||||
|
||||
if (x instanceof C) {
|
||||
>x : Symbol(x, Decl(controlFlowInstanceof.ts, 50, 13))
|
||||
>C : Symbol(C, Decl(controlFlowInstanceof.ts, 47, 31))
|
||||
|
||||
x; // B & C
|
||||
>x : Symbol(x, Decl(controlFlowInstanceof.ts, 50, 13))
|
||||
}
|
||||
else {
|
||||
x; // B
|
||||
>x : Symbol(x, Decl(controlFlowInstanceof.ts, 50, 13))
|
||||
}
|
||||
x; // B
|
||||
>x : Symbol(x, Decl(controlFlowInstanceof.ts, 50, 13))
|
||||
}
|
||||
else {
|
||||
x; // A
|
||||
>x : Symbol(x, Decl(controlFlowInstanceof.ts, 50, 13))
|
||||
}
|
||||
x; // A
|
||||
>x : Symbol(x, Decl(controlFlowInstanceof.ts, 50, 13))
|
||||
}
|
||||
|
||||
// X is neither assignable to Y nor a subtype of Y
|
||||
// Y is assignable to X, but not a subtype of X
|
||||
|
||||
interface X {
|
||||
>X : Symbol(X, Decl(controlFlowInstanceof.ts, 78, 1))
|
||||
|
||||
x?: string;
|
||||
>x : Symbol(X.x, Decl(controlFlowInstanceof.ts, 83, 13))
|
||||
}
|
||||
|
||||
class Y {
|
||||
>Y : Symbol(Y, Decl(controlFlowInstanceof.ts, 85, 1))
|
||||
|
||||
y: string;
|
||||
>y : Symbol(Y.y, Decl(controlFlowInstanceof.ts, 87, 9))
|
||||
}
|
||||
|
||||
function goo(x: X) {
|
||||
>goo : Symbol(goo, Decl(controlFlowInstanceof.ts, 89, 1))
|
||||
>x : Symbol(x, Decl(controlFlowInstanceof.ts, 91, 13))
|
||||
>X : Symbol(X, Decl(controlFlowInstanceof.ts, 78, 1))
|
||||
|
||||
x;
|
||||
>x : Symbol(x, Decl(controlFlowInstanceof.ts, 91, 13))
|
||||
|
||||
if (x instanceof Y) {
|
||||
>x : Symbol(x, Decl(controlFlowInstanceof.ts, 91, 13))
|
||||
>Y : Symbol(Y, Decl(controlFlowInstanceof.ts, 85, 1))
|
||||
|
||||
x.y;
|
||||
>x.y : Symbol(Y.y, Decl(controlFlowInstanceof.ts, 87, 9))
|
||||
>x : Symbol(x, Decl(controlFlowInstanceof.ts, 91, 13))
|
||||
>y : Symbol(Y.y, Decl(controlFlowInstanceof.ts, 87, 9))
|
||||
}
|
||||
x;
|
||||
>x : Symbol(x, Decl(controlFlowInstanceof.ts, 91, 13))
|
||||
}
|
256
tests/baselines/reference/controlFlowInstanceof.types
Normal file
256
tests/baselines/reference/controlFlowInstanceof.types
Normal file
|
@ -0,0 +1,256 @@
|
|||
=== tests/cases/compiler/controlFlowInstanceof.ts ===
|
||||
|
||||
// Repros from #10167
|
||||
|
||||
function f1(s: Set<string> | Set<number>) {
|
||||
>f1 : (s: Set<string> | Set<number>) => void
|
||||
>s : Set<string> | Set<number>
|
||||
>Set : Set<T>
|
||||
>Set : Set<T>
|
||||
|
||||
s = new Set<number>();
|
||||
>s = new Set<number>() : Set<number>
|
||||
>s : Set<string> | Set<number>
|
||||
>new Set<number>() : Set<number>
|
||||
>Set : SetConstructor
|
||||
|
||||
s; // Set<number>
|
||||
>s : Set<number>
|
||||
|
||||
if (s instanceof Set) {
|
||||
>s instanceof Set : boolean
|
||||
>s : Set<number>
|
||||
>Set : SetConstructor
|
||||
|
||||
s; // Set<number>
|
||||
>s : Set<number>
|
||||
}
|
||||
s; // Set<number>
|
||||
>s : Set<number>
|
||||
|
||||
s.add(42);
|
||||
>s.add(42) : Set<number>
|
||||
>s.add : (value: number) => Set<number>
|
||||
>s : Set<number>
|
||||
>add : (value: number) => Set<number>
|
||||
>42 : number
|
||||
}
|
||||
|
||||
function f2(s: Set<string> | Set<number>) {
|
||||
>f2 : (s: Set<string> | Set<number>) => void
|
||||
>s : Set<string> | Set<number>
|
||||
>Set : Set<T>
|
||||
>Set : Set<T>
|
||||
|
||||
s = new Set<number>();
|
||||
>s = new Set<number>() : Set<number>
|
||||
>s : Set<string> | Set<number>
|
||||
>new Set<number>() : Set<number>
|
||||
>Set : SetConstructor
|
||||
|
||||
s; // Set<number>
|
||||
>s : Set<number>
|
||||
|
||||
if (s instanceof Promise) {
|
||||
>s instanceof Promise : boolean
|
||||
>s : Set<number>
|
||||
>Promise : PromiseConstructor
|
||||
|
||||
s; // Set<number> & Promise<any>
|
||||
>s : Set<number> & Promise<any>
|
||||
}
|
||||
s; // Set<number>
|
||||
>s : Set<number>
|
||||
|
||||
s.add(42);
|
||||
>s.add(42) : Set<number>
|
||||
>s.add : (value: number) => Set<number>
|
||||
>s : Set<number>
|
||||
>add : (value: number) => Set<number>
|
||||
>42 : number
|
||||
}
|
||||
|
||||
function f3(s: Set<string> | Set<number>) {
|
||||
>f3 : (s: Set<string> | Set<number>) => void
|
||||
>s : Set<string> | Set<number>
|
||||
>Set : Set<T>
|
||||
>Set : Set<T>
|
||||
|
||||
s; // Set<string> | Set<number>
|
||||
>s : Set<string> | Set<number>
|
||||
|
||||
if (s instanceof Set) {
|
||||
>s instanceof Set : boolean
|
||||
>s : Set<string> | Set<number>
|
||||
>Set : SetConstructor
|
||||
|
||||
s; // Set<string> | Set<number>
|
||||
>s : Set<string> | Set<number>
|
||||
}
|
||||
else {
|
||||
s; // never
|
||||
>s : never
|
||||
}
|
||||
}
|
||||
|
||||
function f4(s: Set<string> | Set<number>) {
|
||||
>f4 : (s: Set<string> | Set<number>) => void
|
||||
>s : Set<string> | Set<number>
|
||||
>Set : Set<T>
|
||||
>Set : Set<T>
|
||||
|
||||
s = new Set<number>();
|
||||
>s = new Set<number>() : Set<number>
|
||||
>s : Set<string> | Set<number>
|
||||
>new Set<number>() : Set<number>
|
||||
>Set : SetConstructor
|
||||
|
||||
s; // Set<number>
|
||||
>s : Set<number>
|
||||
|
||||
if (s instanceof Set) {
|
||||
>s instanceof Set : boolean
|
||||
>s : Set<number>
|
||||
>Set : SetConstructor
|
||||
|
||||
s; // Set<number>
|
||||
>s : Set<number>
|
||||
}
|
||||
else {
|
||||
s; // never
|
||||
>s : never
|
||||
}
|
||||
}
|
||||
|
||||
// More tests
|
||||
|
||||
class A { a: string }
|
||||
>A : A
|
||||
>a : string
|
||||
|
||||
class B extends A { b: string }
|
||||
>B : B
|
||||
>A : A
|
||||
>b : string
|
||||
|
||||
class C extends A { c: string }
|
||||
>C : C
|
||||
>A : A
|
||||
>c : string
|
||||
|
||||
function foo(x: A | undefined) {
|
||||
>foo : (x: A) => void
|
||||
>x : A
|
||||
>A : A
|
||||
|
||||
x; // A | undefined
|
||||
>x : A
|
||||
|
||||
if (x instanceof B || x instanceof C) {
|
||||
>x instanceof B || x instanceof C : boolean
|
||||
>x instanceof B : boolean
|
||||
>x : A
|
||||
>B : typeof B
|
||||
>x instanceof C : boolean
|
||||
>x : A
|
||||
>C : typeof C
|
||||
|
||||
x; // B | C
|
||||
>x : B | C
|
||||
}
|
||||
x; // A | undefined
|
||||
>x : A
|
||||
|
||||
if (x instanceof B && x instanceof C) {
|
||||
>x instanceof B && x instanceof C : boolean
|
||||
>x instanceof B : boolean
|
||||
>x : A
|
||||
>B : typeof B
|
||||
>x instanceof C : boolean
|
||||
>x : B
|
||||
>C : typeof C
|
||||
|
||||
x; // B & C
|
||||
>x : B & C
|
||||
}
|
||||
x; // A | undefined
|
||||
>x : A
|
||||
|
||||
if (!x) {
|
||||
>!x : boolean
|
||||
>x : A
|
||||
|
||||
return;
|
||||
}
|
||||
x; // A
|
||||
>x : A
|
||||
|
||||
if (x instanceof B) {
|
||||
>x instanceof B : boolean
|
||||
>x : A
|
||||
>B : typeof B
|
||||
|
||||
x; // B
|
||||
>x : B
|
||||
|
||||
if (x instanceof C) {
|
||||
>x instanceof C : boolean
|
||||
>x : B
|
||||
>C : typeof C
|
||||
|
||||
x; // B & C
|
||||
>x : B & C
|
||||
}
|
||||
else {
|
||||
x; // B
|
||||
>x : B
|
||||
}
|
||||
x; // B
|
||||
>x : B
|
||||
}
|
||||
else {
|
||||
x; // A
|
||||
>x : A
|
||||
}
|
||||
x; // A
|
||||
>x : A
|
||||
}
|
||||
|
||||
// X is neither assignable to Y nor a subtype of Y
|
||||
// Y is assignable to X, but not a subtype of X
|
||||
|
||||
interface X {
|
||||
>X : X
|
||||
|
||||
x?: string;
|
||||
>x : string
|
||||
}
|
||||
|
||||
class Y {
|
||||
>Y : Y
|
||||
|
||||
y: string;
|
||||
>y : string
|
||||
}
|
||||
|
||||
function goo(x: X) {
|
||||
>goo : (x: X) => void
|
||||
>x : X
|
||||
>X : X
|
||||
|
||||
x;
|
||||
>x : X
|
||||
|
||||
if (x instanceof Y) {
|
||||
>x instanceof Y : boolean
|
||||
>x : X
|
||||
>Y : typeof Y
|
||||
|
||||
x.y;
|
||||
>x.y : string
|
||||
>x : Y
|
||||
>y : string
|
||||
}
|
||||
x;
|
||||
>x : X
|
||||
}
|
59
tests/baselines/reference/discriminantsAndTypePredicates.js
Normal file
59
tests/baselines/reference/discriminantsAndTypePredicates.js
Normal file
|
@ -0,0 +1,59 @@
|
|||
//// [discriminantsAndTypePredicates.ts]
|
||||
// Repro from #10145
|
||||
|
||||
interface A { type: 'A' }
|
||||
interface B { type: 'B' }
|
||||
|
||||
function isA(x: A | B): x is A { return x.type === 'A'; }
|
||||
function isB(x: A | B): x is B { return x.type === 'B'; }
|
||||
|
||||
function foo1(x: A | B): any {
|
||||
x; // A | B
|
||||
if (isA(x)) {
|
||||
return x; // A
|
||||
}
|
||||
x; // B
|
||||
if (isB(x)) {
|
||||
return x; // B
|
||||
}
|
||||
x; // never
|
||||
}
|
||||
|
||||
function foo2(x: A | B): any {
|
||||
x; // A | B
|
||||
if (x.type === 'A') {
|
||||
return x; // A
|
||||
}
|
||||
x; // B
|
||||
if (x.type === 'B') {
|
||||
return x; // B
|
||||
}
|
||||
x; // never
|
||||
}
|
||||
|
||||
//// [discriminantsAndTypePredicates.js]
|
||||
// Repro from #10145
|
||||
function isA(x) { return x.type === 'A'; }
|
||||
function isB(x) { return x.type === 'B'; }
|
||||
function foo1(x) {
|
||||
x; // A | B
|
||||
if (isA(x)) {
|
||||
return x; // A
|
||||
}
|
||||
x; // B
|
||||
if (isB(x)) {
|
||||
return x; // B
|
||||
}
|
||||
x; // never
|
||||
}
|
||||
function foo2(x) {
|
||||
x; // A | B
|
||||
if (x.type === 'A') {
|
||||
return x; // A
|
||||
}
|
||||
x; // B
|
||||
if (x.type === 'B') {
|
||||
return x; // B
|
||||
}
|
||||
x; // never
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
=== tests/cases/compiler/discriminantsAndTypePredicates.ts ===
|
||||
// Repro from #10145
|
||||
|
||||
interface A { type: 'A' }
|
||||
>A : Symbol(A, Decl(discriminantsAndTypePredicates.ts, 0, 0))
|
||||
>type : Symbol(A.type, Decl(discriminantsAndTypePredicates.ts, 2, 13))
|
||||
|
||||
interface B { type: 'B' }
|
||||
>B : Symbol(B, Decl(discriminantsAndTypePredicates.ts, 2, 25))
|
||||
>type : Symbol(B.type, Decl(discriminantsAndTypePredicates.ts, 3, 13))
|
||||
|
||||
function isA(x: A | B): x is A { return x.type === 'A'; }
|
||||
>isA : Symbol(isA, Decl(discriminantsAndTypePredicates.ts, 3, 25))
|
||||
>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 5, 13))
|
||||
>A : Symbol(A, Decl(discriminantsAndTypePredicates.ts, 0, 0))
|
||||
>B : Symbol(B, Decl(discriminantsAndTypePredicates.ts, 2, 25))
|
||||
>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 5, 13))
|
||||
>A : Symbol(A, Decl(discriminantsAndTypePredicates.ts, 0, 0))
|
||||
>x.type : Symbol(type, Decl(discriminantsAndTypePredicates.ts, 2, 13), Decl(discriminantsAndTypePredicates.ts, 3, 13))
|
||||
>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 5, 13))
|
||||
>type : Symbol(type, Decl(discriminantsAndTypePredicates.ts, 2, 13), Decl(discriminantsAndTypePredicates.ts, 3, 13))
|
||||
|
||||
function isB(x: A | B): x is B { return x.type === 'B'; }
|
||||
>isB : Symbol(isB, Decl(discriminantsAndTypePredicates.ts, 5, 57))
|
||||
>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 6, 13))
|
||||
>A : Symbol(A, Decl(discriminantsAndTypePredicates.ts, 0, 0))
|
||||
>B : Symbol(B, Decl(discriminantsAndTypePredicates.ts, 2, 25))
|
||||
>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 6, 13))
|
||||
>B : Symbol(B, Decl(discriminantsAndTypePredicates.ts, 2, 25))
|
||||
>x.type : Symbol(type, Decl(discriminantsAndTypePredicates.ts, 2, 13), Decl(discriminantsAndTypePredicates.ts, 3, 13))
|
||||
>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 6, 13))
|
||||
>type : Symbol(type, Decl(discriminantsAndTypePredicates.ts, 2, 13), Decl(discriminantsAndTypePredicates.ts, 3, 13))
|
||||
|
||||
function foo1(x: A | B): any {
|
||||
>foo1 : Symbol(foo1, Decl(discriminantsAndTypePredicates.ts, 6, 57))
|
||||
>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 8, 14))
|
||||
>A : Symbol(A, Decl(discriminantsAndTypePredicates.ts, 0, 0))
|
||||
>B : Symbol(B, Decl(discriminantsAndTypePredicates.ts, 2, 25))
|
||||
|
||||
x; // A | B
|
||||
>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 8, 14))
|
||||
|
||||
if (isA(x)) {
|
||||
>isA : Symbol(isA, Decl(discriminantsAndTypePredicates.ts, 3, 25))
|
||||
>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 8, 14))
|
||||
|
||||
return x; // A
|
||||
>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 8, 14))
|
||||
}
|
||||
x; // B
|
||||
>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 8, 14))
|
||||
|
||||
if (isB(x)) {
|
||||
>isB : Symbol(isB, Decl(discriminantsAndTypePredicates.ts, 5, 57))
|
||||
>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 8, 14))
|
||||
|
||||
return x; // B
|
||||
>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 8, 14))
|
||||
}
|
||||
x; // never
|
||||
>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 8, 14))
|
||||
}
|
||||
|
||||
function foo2(x: A | B): any {
|
||||
>foo2 : Symbol(foo2, Decl(discriminantsAndTypePredicates.ts, 18, 1))
|
||||
>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 20, 14))
|
||||
>A : Symbol(A, Decl(discriminantsAndTypePredicates.ts, 0, 0))
|
||||
>B : Symbol(B, Decl(discriminantsAndTypePredicates.ts, 2, 25))
|
||||
|
||||
x; // A | B
|
||||
>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 20, 14))
|
||||
|
||||
if (x.type === 'A') {
|
||||
>x.type : Symbol(type, Decl(discriminantsAndTypePredicates.ts, 2, 13), Decl(discriminantsAndTypePredicates.ts, 3, 13))
|
||||
>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 20, 14))
|
||||
>type : Symbol(type, Decl(discriminantsAndTypePredicates.ts, 2, 13), Decl(discriminantsAndTypePredicates.ts, 3, 13))
|
||||
|
||||
return x; // A
|
||||
>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 20, 14))
|
||||
}
|
||||
x; // B
|
||||
>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 20, 14))
|
||||
|
||||
if (x.type === 'B') {
|
||||
>x.type : Symbol(B.type, Decl(discriminantsAndTypePredicates.ts, 3, 13))
|
||||
>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 20, 14))
|
||||
>type : Symbol(B.type, Decl(discriminantsAndTypePredicates.ts, 3, 13))
|
||||
|
||||
return x; // B
|
||||
>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 20, 14))
|
||||
}
|
||||
x; // never
|
||||
>x : Symbol(x, Decl(discriminantsAndTypePredicates.ts, 20, 14))
|
||||
}
|
104
tests/baselines/reference/discriminantsAndTypePredicates.types
Normal file
104
tests/baselines/reference/discriminantsAndTypePredicates.types
Normal file
|
@ -0,0 +1,104 @@
|
|||
=== tests/cases/compiler/discriminantsAndTypePredicates.ts ===
|
||||
// Repro from #10145
|
||||
|
||||
interface A { type: 'A' }
|
||||
>A : A
|
||||
>type : "A"
|
||||
|
||||
interface B { type: 'B' }
|
||||
>B : B
|
||||
>type : "B"
|
||||
|
||||
function isA(x: A | B): x is A { return x.type === 'A'; }
|
||||
>isA : (x: A | B) => x is A
|
||||
>x : A | B
|
||||
>A : A
|
||||
>B : B
|
||||
>x : any
|
||||
>A : A
|
||||
>x.type === 'A' : boolean
|
||||
>x.type : "A" | "B"
|
||||
>x : A | B
|
||||
>type : "A" | "B"
|
||||
>'A' : "A"
|
||||
|
||||
function isB(x: A | B): x is B { return x.type === 'B'; }
|
||||
>isB : (x: A | B) => x is B
|
||||
>x : A | B
|
||||
>A : A
|
||||
>B : B
|
||||
>x : any
|
||||
>B : B
|
||||
>x.type === 'B' : boolean
|
||||
>x.type : "A" | "B"
|
||||
>x : A | B
|
||||
>type : "A" | "B"
|
||||
>'B' : "B"
|
||||
|
||||
function foo1(x: A | B): any {
|
||||
>foo1 : (x: A | B) => any
|
||||
>x : A | B
|
||||
>A : A
|
||||
>B : B
|
||||
|
||||
x; // A | B
|
||||
>x : A | B
|
||||
|
||||
if (isA(x)) {
|
||||
>isA(x) : boolean
|
||||
>isA : (x: A | B) => x is A
|
||||
>x : A | B
|
||||
|
||||
return x; // A
|
||||
>x : A
|
||||
}
|
||||
x; // B
|
||||
>x : B
|
||||
|
||||
if (isB(x)) {
|
||||
>isB(x) : boolean
|
||||
>isB : (x: A | B) => x is B
|
||||
>x : B
|
||||
|
||||
return x; // B
|
||||
>x : B
|
||||
}
|
||||
x; // never
|
||||
>x : never
|
||||
}
|
||||
|
||||
function foo2(x: A | B): any {
|
||||
>foo2 : (x: A | B) => any
|
||||
>x : A | B
|
||||
>A : A
|
||||
>B : B
|
||||
|
||||
x; // A | B
|
||||
>x : A | B
|
||||
|
||||
if (x.type === 'A') {
|
||||
>x.type === 'A' : boolean
|
||||
>x.type : "A" | "B"
|
||||
>x : A | B
|
||||
>type : "A" | "B"
|
||||
>'A' : "A"
|
||||
|
||||
return x; // A
|
||||
>x : A
|
||||
}
|
||||
x; // B
|
||||
>x : B
|
||||
|
||||
if (x.type === 'B') {
|
||||
>x.type === 'B' : boolean
|
||||
>x.type : "B"
|
||||
>x : B
|
||||
>type : "B"
|
||||
>'B' : "B"
|
||||
|
||||
return x; // B
|
||||
>x : B
|
||||
}
|
||||
x; // never
|
||||
>x : never
|
||||
}
|
|
@ -99,8 +99,8 @@ if (hasKind(x, "A")) {
|
|||
}
|
||||
else {
|
||||
let b = x;
|
||||
>b : A
|
||||
>x : A
|
||||
>b : never
|
||||
>x : never
|
||||
}
|
||||
|
||||
if (!hasKind(x, "B")) {
|
||||
|
|
|
@ -93,8 +93,8 @@ if (hasKind(x, "A")) {
|
|||
}
|
||||
else {
|
||||
let b = x;
|
||||
>b : A
|
||||
>x : A
|
||||
>b : never
|
||||
>x : never
|
||||
}
|
||||
|
||||
if (!hasKind(x, "B")) {
|
||||
|
|
|
@ -96,8 +96,8 @@ if (hasKind(x, "A")) {
|
|||
}
|
||||
else {
|
||||
let b = x;
|
||||
>b : A
|
||||
>x : A
|
||||
>b : never
|
||||
>x : never
|
||||
}
|
||||
|
||||
if (!hasKind(x, "B")) {
|
||||
|
|
99
tests/cases/compiler/controlFlowInstanceof.ts
Normal file
99
tests/cases/compiler/controlFlowInstanceof.ts
Normal file
|
@ -0,0 +1,99 @@
|
|||
// @target: es6
|
||||
|
||||
// Repros from #10167
|
||||
|
||||
function f1(s: Set<string> | Set<number>) {
|
||||
s = new Set<number>();
|
||||
s; // Set<number>
|
||||
if (s instanceof Set) {
|
||||
s; // Set<number>
|
||||
}
|
||||
s; // Set<number>
|
||||
s.add(42);
|
||||
}
|
||||
|
||||
function f2(s: Set<string> | Set<number>) {
|
||||
s = new Set<number>();
|
||||
s; // Set<number>
|
||||
if (s instanceof Promise) {
|
||||
s; // Set<number> & Promise<any>
|
||||
}
|
||||
s; // Set<number>
|
||||
s.add(42);
|
||||
}
|
||||
|
||||
function f3(s: Set<string> | Set<number>) {
|
||||
s; // Set<string> | Set<number>
|
||||
if (s instanceof Set) {
|
||||
s; // Set<string> | Set<number>
|
||||
}
|
||||
else {
|
||||
s; // never
|
||||
}
|
||||
}
|
||||
|
||||
function f4(s: Set<string> | Set<number>) {
|
||||
s = new Set<number>();
|
||||
s; // Set<number>
|
||||
if (s instanceof Set) {
|
||||
s; // Set<number>
|
||||
}
|
||||
else {
|
||||
s; // never
|
||||
}
|
||||
}
|
||||
|
||||
// More tests
|
||||
|
||||
class A { a: string }
|
||||
class B extends A { b: string }
|
||||
class C extends A { c: string }
|
||||
|
||||
function foo(x: A | undefined) {
|
||||
x; // A | undefined
|
||||
if (x instanceof B || x instanceof C) {
|
||||
x; // B | C
|
||||
}
|
||||
x; // A | undefined
|
||||
if (x instanceof B && x instanceof C) {
|
||||
x; // B & C
|
||||
}
|
||||
x; // A | undefined
|
||||
if (!x) {
|
||||
return;
|
||||
}
|
||||
x; // A
|
||||
if (x instanceof B) {
|
||||
x; // B
|
||||
if (x instanceof C) {
|
||||
x; // B & C
|
||||
}
|
||||
else {
|
||||
x; // B
|
||||
}
|
||||
x; // B
|
||||
}
|
||||
else {
|
||||
x; // A
|
||||
}
|
||||
x; // A
|
||||
}
|
||||
|
||||
// X is neither assignable to Y nor a subtype of Y
|
||||
// Y is assignable to X, but not a subtype of X
|
||||
|
||||
interface X {
|
||||
x?: string;
|
||||
}
|
||||
|
||||
class Y {
|
||||
y: string;
|
||||
}
|
||||
|
||||
function goo(x: X) {
|
||||
x;
|
||||
if (x instanceof Y) {
|
||||
x.y;
|
||||
}
|
||||
x;
|
||||
}
|
31
tests/cases/compiler/discriminantsAndTypePredicates.ts
Normal file
31
tests/cases/compiler/discriminantsAndTypePredicates.ts
Normal file
|
@ -0,0 +1,31 @@
|
|||
// Repro from #10145
|
||||
|
||||
interface A { type: 'A' }
|
||||
interface B { type: 'B' }
|
||||
|
||||
function isA(x: A | B): x is A { return x.type === 'A'; }
|
||||
function isB(x: A | B): x is B { return x.type === 'B'; }
|
||||
|
||||
function foo1(x: A | B): any {
|
||||
x; // A | B
|
||||
if (isA(x)) {
|
||||
return x; // A
|
||||
}
|
||||
x; // B
|
||||
if (isB(x)) {
|
||||
return x; // B
|
||||
}
|
||||
x; // never
|
||||
}
|
||||
|
||||
function foo2(x: A | B): any {
|
||||
x; // A | B
|
||||
if (x.type === 'A') {
|
||||
return x; // A
|
||||
}
|
||||
x; // B
|
||||
if (x.type === 'B') {
|
||||
return x; // B
|
||||
}
|
||||
x; // never
|
||||
}
|
Loading…
Reference in a new issue