mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-20 05:17:43 -05:00
Merge pull request #10216 from Microsoft/structurallyIdenticalInstanceof
Improve instanceof with structurally identical types
This commit is contained in:
@@ -5924,6 +5924,13 @@ namespace ts {
|
||||
return isTypeRelatedTo(source, target, assignableRelation);
|
||||
}
|
||||
|
||||
// A type S is considered to be an instance of a type T if S and T are the same type or if S is a
|
||||
// subtype of T but not structurally identical to T. This specifically means that two distinct but
|
||||
// structurally identical types (such as two classes) are not considered instances of each other.
|
||||
function isTypeInstanceOf(source: Type, target: Type): boolean {
|
||||
return source === target || isTypeSubtypeOf(source, target) && !isTypeIdenticalTo(source, target);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is *not* a bi-directional relationship.
|
||||
* If one needs to check both directions for comparability, use a second call to this function or 'checkTypeComparableTo'.
|
||||
@@ -8575,12 +8582,12 @@ namespace ts {
|
||||
|
||||
function getNarrowedType(type: Type, candidate: Type, assumeTrue: boolean) {
|
||||
if (!assumeTrue) {
|
||||
return filterType(type, t => !isTypeSubtypeOf(t, candidate));
|
||||
return filterType(type, t => !isTypeInstanceOf(t, candidate));
|
||||
}
|
||||
// If the current type is a union type, remove all constituents that aren't assignable to
|
||||
// If the current type is a union type, remove all constituents that couldn't be instances of
|
||||
// the candidate type. If one or more constituents remain, return a union of those.
|
||||
if (type.flags & TypeFlags.Union) {
|
||||
const assignableConstituents = filter((<UnionType>type).types, t => isTypeAssignableTo(t, candidate));
|
||||
const assignableConstituents = filter((<UnionType>type).types, t => isTypeInstanceOf(t, candidate));
|
||||
if (assignableConstituents.length) {
|
||||
return getUnionType(assignableConstituents);
|
||||
}
|
||||
|
||||
@@ -64,9 +64,9 @@ if (isNodeList(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))
|
||||
}
|
||||
|
||||
if (isHTMLCollection(sourceObj)) {
|
||||
@@ -74,9 +74,9 @@ if (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(HTMLCollection.length, Decl(controlFlowBinaryOrExpression.ts, 14, 33))
|
||||
>sourceObj : Symbol(sourceObj, Decl(controlFlowBinaryOrExpression.ts, 23, 3))
|
||||
>length : Symbol(length, Decl(controlFlowBinaryOrExpression.ts, 10, 27), Decl(controlFlowBinaryOrExpression.ts, 14, 33))
|
||||
>length : Symbol(HTMLCollection.length, Decl(controlFlowBinaryOrExpression.ts, 14, 33))
|
||||
}
|
||||
|
||||
if (isNodeList(sourceObj) || isHTMLCollection(sourceObj)) {
|
||||
@@ -86,8 +86,8 @@ if (isNodeList(sourceObj) || isHTMLCollection(sourceObj)) {
|
||||
>sourceObj : Symbol(sourceObj, Decl(controlFlowBinaryOrExpression.ts, 23, 3))
|
||||
|
||||
sourceObj.length;
|
||||
>sourceObj.length : Symbol(NodeList.length, Decl(controlFlowBinaryOrExpression.ts, 10, 27))
|
||||
>sourceObj.length : Symbol(length, Decl(controlFlowBinaryOrExpression.ts, 10, 27), Decl(controlFlowBinaryOrExpression.ts, 14, 33))
|
||||
>sourceObj : Symbol(sourceObj, Decl(controlFlowBinaryOrExpression.ts, 23, 3))
|
||||
>length : Symbol(NodeList.length, Decl(controlFlowBinaryOrExpression.ts, 10, 27))
|
||||
>length : Symbol(length, Decl(controlFlowBinaryOrExpression.ts, 10, 27), Decl(controlFlowBinaryOrExpression.ts, 14, 33))
|
||||
}
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ if (isNodeList(sourceObj)) {
|
||||
|
||||
sourceObj.length;
|
||||
>sourceObj.length : number
|
||||
>sourceObj : NodeList | HTMLCollection
|
||||
>sourceObj : NodeList
|
||||
>length : number
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ if (isHTMLCollection(sourceObj)) {
|
||||
|
||||
sourceObj.length;
|
||||
>sourceObj.length : number
|
||||
>sourceObj : NodeList | HTMLCollection
|
||||
>sourceObj : HTMLCollection
|
||||
>length : number
|
||||
}
|
||||
|
||||
@@ -102,11 +102,11 @@ if (isNodeList(sourceObj) || isHTMLCollection(sourceObj)) {
|
||||
>sourceObj : EventTargetLike
|
||||
>isHTMLCollection(sourceObj) : boolean
|
||||
>isHTMLCollection : (sourceObj: any) => sourceObj is HTMLCollection
|
||||
>sourceObj : { a: string; }
|
||||
>sourceObj : HTMLCollection | { a: string; }
|
||||
|
||||
sourceObj.length;
|
||||
>sourceObj.length : number
|
||||
>sourceObj : NodeList
|
||||
>sourceObj : NodeList | HTMLCollection
|
||||
>length : number
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
//// [instanceofWithStructurallyIdenticalTypes.ts]
|
||||
// Repro from #7271
|
||||
|
||||
class C1 { item: string }
|
||||
class C2 { item: string[] }
|
||||
class C3 { item: string }
|
||||
|
||||
function foo1(x: C1 | C2 | C3): string {
|
||||
if (x instanceof C1) {
|
||||
return x.item;
|
||||
}
|
||||
else if (x instanceof C2) {
|
||||
return x.item[0];
|
||||
}
|
||||
else if (x instanceof C3) {
|
||||
return x.item;
|
||||
}
|
||||
return "error";
|
||||
}
|
||||
|
||||
function isC1(c: C1 | C2 | C3): c is C1 { return c instanceof C1 }
|
||||
function isC2(c: C1 | C2 | C3): c is C2 { return c instanceof C2 }
|
||||
function isC3(c: C1 | C2 | C3): c is C3 { return c instanceof C3 }
|
||||
|
||||
function foo2(x: C1 | C2 | C3): string {
|
||||
if (isC1(x)) {
|
||||
return x.item;
|
||||
}
|
||||
else if (isC2(x)) {
|
||||
return x.item[0];
|
||||
}
|
||||
else if (isC3(x)) {
|
||||
return x.item;
|
||||
}
|
||||
return "error";
|
||||
}
|
||||
|
||||
// More tests
|
||||
|
||||
class A { a: string }
|
||||
class A1 extends A { }
|
||||
class A2 { a: string }
|
||||
class B extends A { b: string }
|
||||
|
||||
function goo(x: A) {
|
||||
if (x instanceof A) {
|
||||
x; // A
|
||||
}
|
||||
else {
|
||||
x; // never
|
||||
}
|
||||
if (x instanceof A1) {
|
||||
x; // A1
|
||||
}
|
||||
else {
|
||||
x; // A
|
||||
}
|
||||
if (x instanceof A2) {
|
||||
x; // A2
|
||||
}
|
||||
else {
|
||||
x; // A
|
||||
}
|
||||
if (x instanceof B) {
|
||||
x; // B
|
||||
}
|
||||
else {
|
||||
x; // A
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//// [instanceofWithStructurallyIdenticalTypes.js]
|
||||
// Repro from #7271
|
||||
var __extends = (this && this.__extends) || function (d, b) {
|
||||
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
|
||||
function __() { this.constructor = d; }
|
||||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
||||
};
|
||||
var C1 = (function () {
|
||||
function C1() {
|
||||
}
|
||||
return C1;
|
||||
}());
|
||||
var C2 = (function () {
|
||||
function C2() {
|
||||
}
|
||||
return C2;
|
||||
}());
|
||||
var C3 = (function () {
|
||||
function C3() {
|
||||
}
|
||||
return C3;
|
||||
}());
|
||||
function foo1(x) {
|
||||
if (x instanceof C1) {
|
||||
return x.item;
|
||||
}
|
||||
else if (x instanceof C2) {
|
||||
return x.item[0];
|
||||
}
|
||||
else if (x instanceof C3) {
|
||||
return x.item;
|
||||
}
|
||||
return "error";
|
||||
}
|
||||
function isC1(c) { return c instanceof C1; }
|
||||
function isC2(c) { return c instanceof C2; }
|
||||
function isC3(c) { return c instanceof C3; }
|
||||
function foo2(x) {
|
||||
if (isC1(x)) {
|
||||
return x.item;
|
||||
}
|
||||
else if (isC2(x)) {
|
||||
return x.item[0];
|
||||
}
|
||||
else if (isC3(x)) {
|
||||
return x.item;
|
||||
}
|
||||
return "error";
|
||||
}
|
||||
// More tests
|
||||
var A = (function () {
|
||||
function A() {
|
||||
}
|
||||
return A;
|
||||
}());
|
||||
var A1 = (function (_super) {
|
||||
__extends(A1, _super);
|
||||
function A1() {
|
||||
_super.apply(this, arguments);
|
||||
}
|
||||
return A1;
|
||||
}(A));
|
||||
var A2 = (function () {
|
||||
function A2() {
|
||||
}
|
||||
return A2;
|
||||
}());
|
||||
var B = (function (_super) {
|
||||
__extends(B, _super);
|
||||
function B() {
|
||||
_super.apply(this, arguments);
|
||||
}
|
||||
return B;
|
||||
}(A));
|
||||
function goo(x) {
|
||||
if (x instanceof A) {
|
||||
x; // A
|
||||
}
|
||||
else {
|
||||
x; // never
|
||||
}
|
||||
if (x instanceof A1) {
|
||||
x; // A1
|
||||
}
|
||||
else {
|
||||
x; // A
|
||||
}
|
||||
if (x instanceof A2) {
|
||||
x; // A2
|
||||
}
|
||||
else {
|
||||
x; // A
|
||||
}
|
||||
if (x instanceof B) {
|
||||
x; // B
|
||||
}
|
||||
else {
|
||||
x; // A
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
=== tests/cases/compiler/instanceofWithStructurallyIdenticalTypes.ts ===
|
||||
// Repro from #7271
|
||||
|
||||
class C1 { item: string }
|
||||
>C1 : Symbol(C1, Decl(instanceofWithStructurallyIdenticalTypes.ts, 0, 0))
|
||||
>item : Symbol(C1.item, Decl(instanceofWithStructurallyIdenticalTypes.ts, 2, 10))
|
||||
|
||||
class C2 { item: string[] }
|
||||
>C2 : Symbol(C2, Decl(instanceofWithStructurallyIdenticalTypes.ts, 2, 25))
|
||||
>item : Symbol(C2.item, Decl(instanceofWithStructurallyIdenticalTypes.ts, 3, 10))
|
||||
|
||||
class C3 { item: string }
|
||||
>C3 : Symbol(C3, Decl(instanceofWithStructurallyIdenticalTypes.ts, 3, 27))
|
||||
>item : Symbol(C3.item, Decl(instanceofWithStructurallyIdenticalTypes.ts, 4, 10))
|
||||
|
||||
function foo1(x: C1 | C2 | C3): string {
|
||||
>foo1 : Symbol(foo1, Decl(instanceofWithStructurallyIdenticalTypes.ts, 4, 25))
|
||||
>x : Symbol(x, Decl(instanceofWithStructurallyIdenticalTypes.ts, 6, 14))
|
||||
>C1 : Symbol(C1, Decl(instanceofWithStructurallyIdenticalTypes.ts, 0, 0))
|
||||
>C2 : Symbol(C2, Decl(instanceofWithStructurallyIdenticalTypes.ts, 2, 25))
|
||||
>C3 : Symbol(C3, Decl(instanceofWithStructurallyIdenticalTypes.ts, 3, 27))
|
||||
|
||||
if (x instanceof C1) {
|
||||
>x : Symbol(x, Decl(instanceofWithStructurallyIdenticalTypes.ts, 6, 14))
|
||||
>C1 : Symbol(C1, Decl(instanceofWithStructurallyIdenticalTypes.ts, 0, 0))
|
||||
|
||||
return x.item;
|
||||
>x.item : Symbol(C1.item, Decl(instanceofWithStructurallyIdenticalTypes.ts, 2, 10))
|
||||
>x : Symbol(x, Decl(instanceofWithStructurallyIdenticalTypes.ts, 6, 14))
|
||||
>item : Symbol(C1.item, Decl(instanceofWithStructurallyIdenticalTypes.ts, 2, 10))
|
||||
}
|
||||
else if (x instanceof C2) {
|
||||
>x : Symbol(x, Decl(instanceofWithStructurallyIdenticalTypes.ts, 6, 14))
|
||||
>C2 : Symbol(C2, Decl(instanceofWithStructurallyIdenticalTypes.ts, 2, 25))
|
||||
|
||||
return x.item[0];
|
||||
>x.item : Symbol(C2.item, Decl(instanceofWithStructurallyIdenticalTypes.ts, 3, 10))
|
||||
>x : Symbol(x, Decl(instanceofWithStructurallyIdenticalTypes.ts, 6, 14))
|
||||
>item : Symbol(C2.item, Decl(instanceofWithStructurallyIdenticalTypes.ts, 3, 10))
|
||||
}
|
||||
else if (x instanceof C3) {
|
||||
>x : Symbol(x, Decl(instanceofWithStructurallyIdenticalTypes.ts, 6, 14))
|
||||
>C3 : Symbol(C3, Decl(instanceofWithStructurallyIdenticalTypes.ts, 3, 27))
|
||||
|
||||
return x.item;
|
||||
>x.item : Symbol(C3.item, Decl(instanceofWithStructurallyIdenticalTypes.ts, 4, 10))
|
||||
>x : Symbol(x, Decl(instanceofWithStructurallyIdenticalTypes.ts, 6, 14))
|
||||
>item : Symbol(C3.item, Decl(instanceofWithStructurallyIdenticalTypes.ts, 4, 10))
|
||||
}
|
||||
return "error";
|
||||
}
|
||||
|
||||
function isC1(c: C1 | C2 | C3): c is C1 { return c instanceof C1 }
|
||||
>isC1 : Symbol(isC1, Decl(instanceofWithStructurallyIdenticalTypes.ts, 17, 1))
|
||||
>c : Symbol(c, Decl(instanceofWithStructurallyIdenticalTypes.ts, 19, 14))
|
||||
>C1 : Symbol(C1, Decl(instanceofWithStructurallyIdenticalTypes.ts, 0, 0))
|
||||
>C2 : Symbol(C2, Decl(instanceofWithStructurallyIdenticalTypes.ts, 2, 25))
|
||||
>C3 : Symbol(C3, Decl(instanceofWithStructurallyIdenticalTypes.ts, 3, 27))
|
||||
>c : Symbol(c, Decl(instanceofWithStructurallyIdenticalTypes.ts, 19, 14))
|
||||
>C1 : Symbol(C1, Decl(instanceofWithStructurallyIdenticalTypes.ts, 0, 0))
|
||||
>c : Symbol(c, Decl(instanceofWithStructurallyIdenticalTypes.ts, 19, 14))
|
||||
>C1 : Symbol(C1, Decl(instanceofWithStructurallyIdenticalTypes.ts, 0, 0))
|
||||
|
||||
function isC2(c: C1 | C2 | C3): c is C2 { return c instanceof C2 }
|
||||
>isC2 : Symbol(isC2, Decl(instanceofWithStructurallyIdenticalTypes.ts, 19, 66))
|
||||
>c : Symbol(c, Decl(instanceofWithStructurallyIdenticalTypes.ts, 20, 14))
|
||||
>C1 : Symbol(C1, Decl(instanceofWithStructurallyIdenticalTypes.ts, 0, 0))
|
||||
>C2 : Symbol(C2, Decl(instanceofWithStructurallyIdenticalTypes.ts, 2, 25))
|
||||
>C3 : Symbol(C3, Decl(instanceofWithStructurallyIdenticalTypes.ts, 3, 27))
|
||||
>c : Symbol(c, Decl(instanceofWithStructurallyIdenticalTypes.ts, 20, 14))
|
||||
>C2 : Symbol(C2, Decl(instanceofWithStructurallyIdenticalTypes.ts, 2, 25))
|
||||
>c : Symbol(c, Decl(instanceofWithStructurallyIdenticalTypes.ts, 20, 14))
|
||||
>C2 : Symbol(C2, Decl(instanceofWithStructurallyIdenticalTypes.ts, 2, 25))
|
||||
|
||||
function isC3(c: C1 | C2 | C3): c is C3 { return c instanceof C3 }
|
||||
>isC3 : Symbol(isC3, Decl(instanceofWithStructurallyIdenticalTypes.ts, 20, 66))
|
||||
>c : Symbol(c, Decl(instanceofWithStructurallyIdenticalTypes.ts, 21, 14))
|
||||
>C1 : Symbol(C1, Decl(instanceofWithStructurallyIdenticalTypes.ts, 0, 0))
|
||||
>C2 : Symbol(C2, Decl(instanceofWithStructurallyIdenticalTypes.ts, 2, 25))
|
||||
>C3 : Symbol(C3, Decl(instanceofWithStructurallyIdenticalTypes.ts, 3, 27))
|
||||
>c : Symbol(c, Decl(instanceofWithStructurallyIdenticalTypes.ts, 21, 14))
|
||||
>C3 : Symbol(C3, Decl(instanceofWithStructurallyIdenticalTypes.ts, 3, 27))
|
||||
>c : Symbol(c, Decl(instanceofWithStructurallyIdenticalTypes.ts, 21, 14))
|
||||
>C3 : Symbol(C3, Decl(instanceofWithStructurallyIdenticalTypes.ts, 3, 27))
|
||||
|
||||
function foo2(x: C1 | C2 | C3): string {
|
||||
>foo2 : Symbol(foo2, Decl(instanceofWithStructurallyIdenticalTypes.ts, 21, 66))
|
||||
>x : Symbol(x, Decl(instanceofWithStructurallyIdenticalTypes.ts, 23, 14))
|
||||
>C1 : Symbol(C1, Decl(instanceofWithStructurallyIdenticalTypes.ts, 0, 0))
|
||||
>C2 : Symbol(C2, Decl(instanceofWithStructurallyIdenticalTypes.ts, 2, 25))
|
||||
>C3 : Symbol(C3, Decl(instanceofWithStructurallyIdenticalTypes.ts, 3, 27))
|
||||
|
||||
if (isC1(x)) {
|
||||
>isC1 : Symbol(isC1, Decl(instanceofWithStructurallyIdenticalTypes.ts, 17, 1))
|
||||
>x : Symbol(x, Decl(instanceofWithStructurallyIdenticalTypes.ts, 23, 14))
|
||||
|
||||
return x.item;
|
||||
>x.item : Symbol(C1.item, Decl(instanceofWithStructurallyIdenticalTypes.ts, 2, 10))
|
||||
>x : Symbol(x, Decl(instanceofWithStructurallyIdenticalTypes.ts, 23, 14))
|
||||
>item : Symbol(C1.item, Decl(instanceofWithStructurallyIdenticalTypes.ts, 2, 10))
|
||||
}
|
||||
else if (isC2(x)) {
|
||||
>isC2 : Symbol(isC2, Decl(instanceofWithStructurallyIdenticalTypes.ts, 19, 66))
|
||||
>x : Symbol(x, Decl(instanceofWithStructurallyIdenticalTypes.ts, 23, 14))
|
||||
|
||||
return x.item[0];
|
||||
>x.item : Symbol(C2.item, Decl(instanceofWithStructurallyIdenticalTypes.ts, 3, 10))
|
||||
>x : Symbol(x, Decl(instanceofWithStructurallyIdenticalTypes.ts, 23, 14))
|
||||
>item : Symbol(C2.item, Decl(instanceofWithStructurallyIdenticalTypes.ts, 3, 10))
|
||||
}
|
||||
else if (isC3(x)) {
|
||||
>isC3 : Symbol(isC3, Decl(instanceofWithStructurallyIdenticalTypes.ts, 20, 66))
|
||||
>x : Symbol(x, Decl(instanceofWithStructurallyIdenticalTypes.ts, 23, 14))
|
||||
|
||||
return x.item;
|
||||
>x.item : Symbol(C3.item, Decl(instanceofWithStructurallyIdenticalTypes.ts, 4, 10))
|
||||
>x : Symbol(x, Decl(instanceofWithStructurallyIdenticalTypes.ts, 23, 14))
|
||||
>item : Symbol(C3.item, Decl(instanceofWithStructurallyIdenticalTypes.ts, 4, 10))
|
||||
}
|
||||
return "error";
|
||||
}
|
||||
|
||||
// More tests
|
||||
|
||||
class A { a: string }
|
||||
>A : Symbol(A, Decl(instanceofWithStructurallyIdenticalTypes.ts, 34, 1))
|
||||
>a : Symbol(A.a, Decl(instanceofWithStructurallyIdenticalTypes.ts, 38, 9))
|
||||
|
||||
class A1 extends A { }
|
||||
>A1 : Symbol(A1, Decl(instanceofWithStructurallyIdenticalTypes.ts, 38, 21))
|
||||
>A : Symbol(A, Decl(instanceofWithStructurallyIdenticalTypes.ts, 34, 1))
|
||||
|
||||
class A2 { a: string }
|
||||
>A2 : Symbol(A2, Decl(instanceofWithStructurallyIdenticalTypes.ts, 39, 22))
|
||||
>a : Symbol(A2.a, Decl(instanceofWithStructurallyIdenticalTypes.ts, 40, 10))
|
||||
|
||||
class B extends A { b: string }
|
||||
>B : Symbol(B, Decl(instanceofWithStructurallyIdenticalTypes.ts, 40, 22))
|
||||
>A : Symbol(A, Decl(instanceofWithStructurallyIdenticalTypes.ts, 34, 1))
|
||||
>b : Symbol(B.b, Decl(instanceofWithStructurallyIdenticalTypes.ts, 41, 19))
|
||||
|
||||
function goo(x: A) {
|
||||
>goo : Symbol(goo, Decl(instanceofWithStructurallyIdenticalTypes.ts, 41, 31))
|
||||
>x : Symbol(x, Decl(instanceofWithStructurallyIdenticalTypes.ts, 43, 13))
|
||||
>A : Symbol(A, Decl(instanceofWithStructurallyIdenticalTypes.ts, 34, 1))
|
||||
|
||||
if (x instanceof A) {
|
||||
>x : Symbol(x, Decl(instanceofWithStructurallyIdenticalTypes.ts, 43, 13))
|
||||
>A : Symbol(A, Decl(instanceofWithStructurallyIdenticalTypes.ts, 34, 1))
|
||||
|
||||
x; // A
|
||||
>x : Symbol(x, Decl(instanceofWithStructurallyIdenticalTypes.ts, 43, 13))
|
||||
}
|
||||
else {
|
||||
x; // never
|
||||
>x : Symbol(x, Decl(instanceofWithStructurallyIdenticalTypes.ts, 43, 13))
|
||||
}
|
||||
if (x instanceof A1) {
|
||||
>x : Symbol(x, Decl(instanceofWithStructurallyIdenticalTypes.ts, 43, 13))
|
||||
>A1 : Symbol(A1, Decl(instanceofWithStructurallyIdenticalTypes.ts, 38, 21))
|
||||
|
||||
x; // A1
|
||||
>x : Symbol(x, Decl(instanceofWithStructurallyIdenticalTypes.ts, 43, 13))
|
||||
}
|
||||
else {
|
||||
x; // A
|
||||
>x : Symbol(x, Decl(instanceofWithStructurallyIdenticalTypes.ts, 43, 13))
|
||||
}
|
||||
if (x instanceof A2) {
|
||||
>x : Symbol(x, Decl(instanceofWithStructurallyIdenticalTypes.ts, 43, 13))
|
||||
>A2 : Symbol(A2, Decl(instanceofWithStructurallyIdenticalTypes.ts, 39, 22))
|
||||
|
||||
x; // A2
|
||||
>x : Symbol(x, Decl(instanceofWithStructurallyIdenticalTypes.ts, 43, 13))
|
||||
}
|
||||
else {
|
||||
x; // A
|
||||
>x : Symbol(x, Decl(instanceofWithStructurallyIdenticalTypes.ts, 43, 13))
|
||||
}
|
||||
if (x instanceof B) {
|
||||
>x : Symbol(x, Decl(instanceofWithStructurallyIdenticalTypes.ts, 43, 13))
|
||||
>B : Symbol(B, Decl(instanceofWithStructurallyIdenticalTypes.ts, 40, 22))
|
||||
|
||||
x; // B
|
||||
>x : Symbol(x, Decl(instanceofWithStructurallyIdenticalTypes.ts, 43, 13))
|
||||
}
|
||||
else {
|
||||
x; // A
|
||||
>x : Symbol(x, Decl(instanceofWithStructurallyIdenticalTypes.ts, 43, 13))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,211 @@
|
||||
=== tests/cases/compiler/instanceofWithStructurallyIdenticalTypes.ts ===
|
||||
// Repro from #7271
|
||||
|
||||
class C1 { item: string }
|
||||
>C1 : C1
|
||||
>item : string
|
||||
|
||||
class C2 { item: string[] }
|
||||
>C2 : C2
|
||||
>item : string[]
|
||||
|
||||
class C3 { item: string }
|
||||
>C3 : C3
|
||||
>item : string
|
||||
|
||||
function foo1(x: C1 | C2 | C3): string {
|
||||
>foo1 : (x: C1 | C2 | C3) => string
|
||||
>x : C1 | C2 | C3
|
||||
>C1 : C1
|
||||
>C2 : C2
|
||||
>C3 : C3
|
||||
|
||||
if (x instanceof C1) {
|
||||
>x instanceof C1 : boolean
|
||||
>x : C1 | C2 | C3
|
||||
>C1 : typeof C1
|
||||
|
||||
return x.item;
|
||||
>x.item : string
|
||||
>x : C1
|
||||
>item : string
|
||||
}
|
||||
else if (x instanceof C2) {
|
||||
>x instanceof C2 : boolean
|
||||
>x : C2 | C3
|
||||
>C2 : typeof C2
|
||||
|
||||
return x.item[0];
|
||||
>x.item[0] : string
|
||||
>x.item : string[]
|
||||
>x : C2
|
||||
>item : string[]
|
||||
>0 : number
|
||||
}
|
||||
else if (x instanceof C3) {
|
||||
>x instanceof C3 : boolean
|
||||
>x : C3
|
||||
>C3 : typeof C3
|
||||
|
||||
return x.item;
|
||||
>x.item : string
|
||||
>x : C3
|
||||
>item : string
|
||||
}
|
||||
return "error";
|
||||
>"error" : string
|
||||
}
|
||||
|
||||
function isC1(c: C1 | C2 | C3): c is C1 { return c instanceof C1 }
|
||||
>isC1 : (c: C1 | C2 | C3) => c is C1
|
||||
>c : C1 | C2 | C3
|
||||
>C1 : C1
|
||||
>C2 : C2
|
||||
>C3 : C3
|
||||
>c : any
|
||||
>C1 : C1
|
||||
>c instanceof C1 : boolean
|
||||
>c : C1 | C2 | C3
|
||||
>C1 : typeof C1
|
||||
|
||||
function isC2(c: C1 | C2 | C3): c is C2 { return c instanceof C2 }
|
||||
>isC2 : (c: C1 | C2 | C3) => c is C2
|
||||
>c : C1 | C2 | C3
|
||||
>C1 : C1
|
||||
>C2 : C2
|
||||
>C3 : C3
|
||||
>c : any
|
||||
>C2 : C2
|
||||
>c instanceof C2 : boolean
|
||||
>c : C1 | C2 | C3
|
||||
>C2 : typeof C2
|
||||
|
||||
function isC3(c: C1 | C2 | C3): c is C3 { return c instanceof C3 }
|
||||
>isC3 : (c: C1 | C2 | C3) => c is C3
|
||||
>c : C1 | C2 | C3
|
||||
>C1 : C1
|
||||
>C2 : C2
|
||||
>C3 : C3
|
||||
>c : any
|
||||
>C3 : C3
|
||||
>c instanceof C3 : boolean
|
||||
>c : C1 | C2 | C3
|
||||
>C3 : typeof C3
|
||||
|
||||
function foo2(x: C1 | C2 | C3): string {
|
||||
>foo2 : (x: C1 | C2 | C3) => string
|
||||
>x : C1 | C2 | C3
|
||||
>C1 : C1
|
||||
>C2 : C2
|
||||
>C3 : C3
|
||||
|
||||
if (isC1(x)) {
|
||||
>isC1(x) : boolean
|
||||
>isC1 : (c: C1 | C2 | C3) => c is C1
|
||||
>x : C1 | C2 | C3
|
||||
|
||||
return x.item;
|
||||
>x.item : string
|
||||
>x : C1
|
||||
>item : string
|
||||
}
|
||||
else if (isC2(x)) {
|
||||
>isC2(x) : boolean
|
||||
>isC2 : (c: C1 | C2 | C3) => c is C2
|
||||
>x : C2 | C3
|
||||
|
||||
return x.item[0];
|
||||
>x.item[0] : string
|
||||
>x.item : string[]
|
||||
>x : C2
|
||||
>item : string[]
|
||||
>0 : number
|
||||
}
|
||||
else if (isC3(x)) {
|
||||
>isC3(x) : boolean
|
||||
>isC3 : (c: C1 | C2 | C3) => c is C3
|
||||
>x : C3
|
||||
|
||||
return x.item;
|
||||
>x.item : string
|
||||
>x : C3
|
||||
>item : string
|
||||
}
|
||||
return "error";
|
||||
>"error" : string
|
||||
}
|
||||
|
||||
// More tests
|
||||
|
||||
class A { a: string }
|
||||
>A : A
|
||||
>a : string
|
||||
|
||||
class A1 extends A { }
|
||||
>A1 : A1
|
||||
>A : A
|
||||
|
||||
class A2 { a: string }
|
||||
>A2 : A2
|
||||
>a : string
|
||||
|
||||
class B extends A { b: string }
|
||||
>B : B
|
||||
>A : A
|
||||
>b : string
|
||||
|
||||
function goo(x: A) {
|
||||
>goo : (x: A) => void
|
||||
>x : A
|
||||
>A : A
|
||||
|
||||
if (x instanceof A) {
|
||||
>x instanceof A : boolean
|
||||
>x : A
|
||||
>A : typeof A
|
||||
|
||||
x; // A
|
||||
>x : A
|
||||
}
|
||||
else {
|
||||
x; // never
|
||||
>x : never
|
||||
}
|
||||
if (x instanceof A1) {
|
||||
>x instanceof A1 : boolean
|
||||
>x : A
|
||||
>A1 : typeof A1
|
||||
|
||||
x; // A1
|
||||
>x : A1
|
||||
}
|
||||
else {
|
||||
x; // A
|
||||
>x : A
|
||||
}
|
||||
if (x instanceof A2) {
|
||||
>x instanceof A2 : boolean
|
||||
>x : A
|
||||
>A2 : typeof A2
|
||||
|
||||
x; // A2
|
||||
>x : A2
|
||||
}
|
||||
else {
|
||||
x; // A
|
||||
>x : A
|
||||
}
|
||||
if (x instanceof B) {
|
||||
>x instanceof B : boolean
|
||||
>x : A
|
||||
>B : typeof B
|
||||
|
||||
x; // B
|
||||
>x : B
|
||||
}
|
||||
else {
|
||||
x; // A
|
||||
>x : A
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
// Repro from #7271
|
||||
|
||||
class C1 { item: string }
|
||||
class C2 { item: string[] }
|
||||
class C3 { item: string }
|
||||
|
||||
function foo1(x: C1 | C2 | C3): string {
|
||||
if (x instanceof C1) {
|
||||
return x.item;
|
||||
}
|
||||
else if (x instanceof C2) {
|
||||
return x.item[0];
|
||||
}
|
||||
else if (x instanceof C3) {
|
||||
return x.item;
|
||||
}
|
||||
return "error";
|
||||
}
|
||||
|
||||
function isC1(c: C1 | C2 | C3): c is C1 { return c instanceof C1 }
|
||||
function isC2(c: C1 | C2 | C3): c is C2 { return c instanceof C2 }
|
||||
function isC3(c: C1 | C2 | C3): c is C3 { return c instanceof C3 }
|
||||
|
||||
function foo2(x: C1 | C2 | C3): string {
|
||||
if (isC1(x)) {
|
||||
return x.item;
|
||||
}
|
||||
else if (isC2(x)) {
|
||||
return x.item[0];
|
||||
}
|
||||
else if (isC3(x)) {
|
||||
return x.item;
|
||||
}
|
||||
return "error";
|
||||
}
|
||||
|
||||
// More tests
|
||||
|
||||
class A { a: string }
|
||||
class A1 extends A { }
|
||||
class A2 { a: string }
|
||||
class B extends A { b: string }
|
||||
|
||||
function goo(x: A) {
|
||||
if (x instanceof A) {
|
||||
x; // A
|
||||
}
|
||||
else {
|
||||
x; // never
|
||||
}
|
||||
if (x instanceof A1) {
|
||||
x; // A1
|
||||
}
|
||||
else {
|
||||
x; // A
|
||||
}
|
||||
if (x instanceof A2) {
|
||||
x; // A2
|
||||
}
|
||||
else {
|
||||
x; // A
|
||||
}
|
||||
if (x instanceof B) {
|
||||
x; // B
|
||||
}
|
||||
else {
|
||||
x; // A
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user