narrowTypeByInstanceof understands ctor funcs (#27551)

* narrowTypeByInstanceof understands ctor funcs

* Rename test filename

* Fix whitespace lint
This commit is contained in:
Nathan Shively-Sanders
2018-10-04 13:52:38 -07:00
committed by GitHub
parent f07404938f
commit 04266aa617
5 changed files with 73 additions and 199 deletions

View File

@@ -15391,9 +15391,12 @@ namespace ts {
}
if (!targetType) {
const constructSignatures = getSignaturesOfType(rightType, SignatureKind.Construct);
targetType = constructSignatures && constructSignatures.length ?
getUnionType(map(constructSignatures, signature => getReturnTypeOfSignature(getErasedSignature(signature)))) :
let constructSignatures = getSignaturesOfType(rightType, SignatureKind.Construct);
if (constructSignatures.length === 0) {
constructSignatures = filter(getSignaturesOfType(rightType, SignatureKind.Call), sig => isJSConstructor(sig.declaration));
}
targetType = constructSignatures.length ?
getUnionType(map(constructSignatures, signature => isJSConstructor(signature.declaration) && getJSClassType(getSymbolOfNode(signature.declaration!)) || getReturnTypeOfSignature(getErasedSignature(signature)))) :
emptyObjectType;
}

View File

@@ -1,196 +0,0 @@
//// [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;
}
// Repro from #27282
declare const x: (() => void)|null;
declare const ctor: Function;
if (x instanceof ctor) {
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;
}
if (x instanceof ctor) {
x();
}

View File

@@ -247,3 +247,28 @@ if (x instanceof ctor) {
>x : Symbol(x, Decl(controlFlowInstanceof.ts, 100, 13))
}
// Repro from #27550 (based on uglify code)
=== tests/cases/compiler/uglify.js ===
/** @constructor */
function AtTop(val) { this.val = val }
>AtTop : Symbol(AtTop, Decl(uglify.js, 0, 0))
>val : Symbol(val, Decl(uglify.js, 1, 15))
>this.val : Symbol(AtTop.val, Decl(uglify.js, 1, 21))
>this : Symbol(AtTop, Decl(uglify.js, 0, 0))
>val : Symbol(AtTop.val, Decl(uglify.js, 1, 21))
>val : Symbol(val, Decl(uglify.js, 1, 15))
/** @type {*} */
var v = 1;
>v : Symbol(v, Decl(uglify.js, 3, 3))
if (v instanceof AtTop) {
>v : Symbol(v, Decl(uglify.js, 3, 3))
>AtTop : Symbol(AtTop, Decl(uglify.js, 0, 0))
v.val
>v.val : Symbol(AtTop.val, Decl(uglify.js, 1, 21))
>v : Symbol(v, Decl(uglify.js, 3, 3))
>val : Symbol(AtTop.val, Decl(uglify.js, 1, 21))
}

View File

@@ -261,3 +261,31 @@ if (x instanceof ctor) {
>x : () => void
}
// Repro from #27550 (based on uglify code)
=== tests/cases/compiler/uglify.js ===
/** @constructor */
function AtTop(val) { this.val = val }
>AtTop : typeof AtTop
>val : any
>this.val = val : any
>this.val : any
>this : AtTop
>val : any
>val : any
/** @type {*} */
var v = 1;
>v : any
>1 : 1
if (v instanceof AtTop) {
>v instanceof AtTop : boolean
>v : any
>AtTop : typeof AtTop
v.val
>v.val : any
>v : AtTop
>val : any
}

View File

@@ -1,6 +1,10 @@
// @target: es6
// @noEmit: true
// @allowJs: true
// @checkJs: true
// @strictNullChecks: true
// @Filename: controlFlowInstanceof.ts
// Repros from #10167
function f1(s: Set<string> | Set<number>) {
@@ -107,3 +111,13 @@ declare const ctor: Function;
if (x instanceof ctor) {
x();
}
// Repro from #27550 (based on uglify code)
// @Filename: uglify.js
/** @constructor */
function AtTop(val) { this.val = val }
/** @type {*} */
var v = 1;
if (v instanceof AtTop) {
v.val
}