mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-10 01:43:59 -05:00
narrowTypeByInstanceof understands ctor funcs (#27551)
* narrowTypeByInstanceof understands ctor funcs * Rename test filename * Fix whitespace lint
This commit is contained in:
committed by
GitHub
parent
f07404938f
commit
04266aa617
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user