Improve handling of corner cases in `narrowTypeByInstanceof` (#52592)
This commit is contained in:
Родитель
7bfe6ac49a
Коммит
720ec45be5
|
@ -27031,42 +27031,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
|||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
// Check that right operand is a function type with a prototype property
|
||||
const rightType = getTypeOfExpression(expr.right);
|
||||
if (!isTypeDerivedFrom(rightType, globalFunctionType)) {
|
||||
return type;
|
||||
}
|
||||
|
||||
let targetType: Type | undefined;
|
||||
const prototypeProperty = getPropertyOfType(rightType, "prototype" as __String);
|
||||
if (prototypeProperty) {
|
||||
// Target type is type of the prototype property
|
||||
const prototypePropertyType = getTypeOfSymbol(prototypeProperty);
|
||||
if (!isTypeAny(prototypePropertyType)) {
|
||||
targetType = prototypePropertyType;
|
||||
}
|
||||
}
|
||||
|
||||
// Don't narrow from 'any' if the target type is exactly 'Object' or 'Function'
|
||||
if (isTypeAny(type) && (targetType === globalObjectType || targetType === globalFunctionType)) {
|
||||
const instanceType = mapType(rightType, getInstanceType);
|
||||
// Don't narrow from `any` if the target type is exactly `Object` or `Function`, and narrow
|
||||
// in the false branch only if the target is a non-empty object type.
|
||||
if (isTypeAny(type) && (instanceType === globalObjectType || instanceType === globalFunctionType) ||
|
||||
!assumeTrue && !(instanceType.flags & TypeFlags.Object && !isEmptyAnonymousObjectType(instanceType))) {
|
||||
return type;
|
||||
}
|
||||
return getNarrowedType(type, instanceType, assumeTrue, /*checkDerived*/ true);
|
||||
}
|
||||
|
||||
if (!targetType) {
|
||||
const constructSignatures = getSignaturesOfType(rightType, SignatureKind.Construct);
|
||||
targetType = constructSignatures.length ?
|
||||
getUnionType(map(constructSignatures, signature => getReturnTypeOfSignature(getErasedSignature(signature)))) :
|
||||
emptyObjectType;
|
||||
function getInstanceType(constructorType: Type) {
|
||||
const prototypePropertyType = getTypeOfPropertyOfType(constructorType, "prototype" as __String);
|
||||
if (prototypePropertyType && !isTypeAny(prototypePropertyType)) {
|
||||
return prototypePropertyType;
|
||||
}
|
||||
|
||||
// We can't narrow a union based off instanceof without negated types see #31576 for more info
|
||||
if (!assumeTrue && rightType.flags & TypeFlags.Union) {
|
||||
const nonConstructorTypeInUnion = find((rightType as UnionType).types, (t) => !isConstructorType(t));
|
||||
if (!nonConstructorTypeInUnion) return type;
|
||||
const constructSignatures = getSignaturesOfType(constructorType, SignatureKind.Construct);
|
||||
if (constructSignatures.length) {
|
||||
return getUnionType(map(constructSignatures, signature => getReturnTypeOfSignature(getErasedSignature(signature))));
|
||||
}
|
||||
|
||||
return getNarrowedType(type, targetType, assumeTrue, /*checkDerived*/ true);
|
||||
// We use the empty object type to indicate we don't know the type of objects created by
|
||||
// this constructor function.
|
||||
return emptyObjectType;
|
||||
}
|
||||
|
||||
function getNarrowedType(type: Type, candidate: Type, assumeTrue: boolean, checkDerived: boolean) {
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
//// [narrowByInstanceof.ts]
|
||||
interface A { a: string }
|
||||
interface B { b: string }
|
||||
interface C { c: string }
|
||||
|
||||
type AA = {
|
||||
(): void;
|
||||
prototype: A;
|
||||
}
|
||||
|
||||
type BB = {
|
||||
new(): B;
|
||||
}
|
||||
|
||||
function foo(x: A | B | C, A: AA, B: BB, AB: AA | BB) {
|
||||
if (x instanceof A) {
|
||||
x; // A
|
||||
}
|
||||
else {
|
||||
x; // B | C
|
||||
}
|
||||
if (x instanceof B) {
|
||||
x; // B
|
||||
}
|
||||
else {
|
||||
x; // A | C
|
||||
}
|
||||
if (x instanceof AB) {
|
||||
x; // A | B
|
||||
}
|
||||
else {
|
||||
x; // A | B | C
|
||||
}
|
||||
}
|
||||
|
||||
function bar(target: any, Promise: any) {
|
||||
if (target instanceof Promise) {
|
||||
target.__then();
|
||||
}
|
||||
}
|
||||
|
||||
// Repro from #52571
|
||||
|
||||
class PersonMixin extends Function {
|
||||
public check(o: any) {
|
||||
return typeof o === "object" && o !== null && o instanceof Person;
|
||||
}
|
||||
}
|
||||
|
||||
const cls = new PersonMixin();
|
||||
|
||||
class Person {
|
||||
work(): void { console.log("work") }
|
||||
sayHi(): void { console.log("Hi") }
|
||||
}
|
||||
|
||||
class Car {
|
||||
sayHi(): void { console.log("Wof Wof") }
|
||||
}
|
||||
|
||||
function test(o: Person | Car) {
|
||||
if (o instanceof cls) {
|
||||
console.log("Is Person");
|
||||
(o as Person).work()
|
||||
}
|
||||
else {
|
||||
console.log("Is Car")
|
||||
o.sayHi();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//// [narrowByInstanceof.js]
|
||||
"use strict";
|
||||
var __extends = (this && this.__extends) || (function () {
|
||||
var extendStatics = function (d, b) {
|
||||
extendStatics = Object.setPrototypeOf ||
|
||||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
||||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
|
||||
return extendStatics(d, b);
|
||||
};
|
||||
return function (d, b) {
|
||||
if (typeof b !== "function" && b !== null)
|
||||
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
||||
extendStatics(d, b);
|
||||
function __() { this.constructor = d; }
|
||||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
||||
};
|
||||
})();
|
||||
function foo(x, A, B, AB) {
|
||||
if (x instanceof A) {
|
||||
x; // A
|
||||
}
|
||||
else {
|
||||
x; // B | C
|
||||
}
|
||||
if (x instanceof B) {
|
||||
x; // B
|
||||
}
|
||||
else {
|
||||
x; // A | C
|
||||
}
|
||||
if (x instanceof AB) {
|
||||
x; // A | B
|
||||
}
|
||||
else {
|
||||
x; // A | B | C
|
||||
}
|
||||
}
|
||||
function bar(target, Promise) {
|
||||
if (target instanceof Promise) {
|
||||
target.__then();
|
||||
}
|
||||
}
|
||||
// Repro from #52571
|
||||
var PersonMixin = /** @class */ (function (_super) {
|
||||
__extends(PersonMixin, _super);
|
||||
function PersonMixin() {
|
||||
return _super !== null && _super.apply(this, arguments) || this;
|
||||
}
|
||||
PersonMixin.prototype.check = function (o) {
|
||||
return typeof o === "object" && o !== null && o instanceof Person;
|
||||
};
|
||||
return PersonMixin;
|
||||
}(Function));
|
||||
var cls = new PersonMixin();
|
||||
var Person = /** @class */ (function () {
|
||||
function Person() {
|
||||
}
|
||||
Person.prototype.work = function () { console.log("work"); };
|
||||
Person.prototype.sayHi = function () { console.log("Hi"); };
|
||||
return Person;
|
||||
}());
|
||||
var Car = /** @class */ (function () {
|
||||
function Car() {
|
||||
}
|
||||
Car.prototype.sayHi = function () { console.log("Wof Wof"); };
|
||||
return Car;
|
||||
}());
|
||||
function test(o) {
|
||||
if (o instanceof cls) {
|
||||
console.log("Is Person");
|
||||
o.work();
|
||||
}
|
||||
else {
|
||||
console.log("Is Car");
|
||||
o.sayHi();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,174 @@
|
|||
=== tests/cases/compiler/narrowByInstanceof.ts ===
|
||||
interface A { a: string }
|
||||
>A : Symbol(A, Decl(narrowByInstanceof.ts, 0, 0))
|
||||
>a : Symbol(A.a, Decl(narrowByInstanceof.ts, 0, 13))
|
||||
|
||||
interface B { b: string }
|
||||
>B : Symbol(B, Decl(narrowByInstanceof.ts, 0, 25))
|
||||
>b : Symbol(B.b, Decl(narrowByInstanceof.ts, 1, 13))
|
||||
|
||||
interface C { c: string }
|
||||
>C : Symbol(C, Decl(narrowByInstanceof.ts, 1, 25))
|
||||
>c : Symbol(C.c, Decl(narrowByInstanceof.ts, 2, 13))
|
||||
|
||||
type AA = {
|
||||
>AA : Symbol(AA, Decl(narrowByInstanceof.ts, 2, 25))
|
||||
|
||||
(): void;
|
||||
prototype: A;
|
||||
>prototype : Symbol(prototype, Decl(narrowByInstanceof.ts, 5, 13))
|
||||
>A : Symbol(A, Decl(narrowByInstanceof.ts, 0, 0))
|
||||
}
|
||||
|
||||
type BB = {
|
||||
>BB : Symbol(BB, Decl(narrowByInstanceof.ts, 7, 1))
|
||||
|
||||
new(): B;
|
||||
>B : Symbol(B, Decl(narrowByInstanceof.ts, 0, 25))
|
||||
}
|
||||
|
||||
function foo(x: A | B | C, A: AA, B: BB, AB: AA | BB) {
|
||||
>foo : Symbol(foo, Decl(narrowByInstanceof.ts, 11, 1))
|
||||
>x : Symbol(x, Decl(narrowByInstanceof.ts, 13, 13))
|
||||
>A : Symbol(A, Decl(narrowByInstanceof.ts, 0, 0))
|
||||
>B : Symbol(B, Decl(narrowByInstanceof.ts, 0, 25))
|
||||
>C : Symbol(C, Decl(narrowByInstanceof.ts, 1, 25))
|
||||
>A : Symbol(A, Decl(narrowByInstanceof.ts, 13, 26))
|
||||
>AA : Symbol(AA, Decl(narrowByInstanceof.ts, 2, 25))
|
||||
>B : Symbol(B, Decl(narrowByInstanceof.ts, 13, 33))
|
||||
>BB : Symbol(BB, Decl(narrowByInstanceof.ts, 7, 1))
|
||||
>AB : Symbol(AB, Decl(narrowByInstanceof.ts, 13, 40))
|
||||
>AA : Symbol(AA, Decl(narrowByInstanceof.ts, 2, 25))
|
||||
>BB : Symbol(BB, Decl(narrowByInstanceof.ts, 7, 1))
|
||||
|
||||
if (x instanceof A) {
|
||||
>x : Symbol(x, Decl(narrowByInstanceof.ts, 13, 13))
|
||||
>A : Symbol(A, Decl(narrowByInstanceof.ts, 13, 26))
|
||||
|
||||
x; // A
|
||||
>x : Symbol(x, Decl(narrowByInstanceof.ts, 13, 13))
|
||||
}
|
||||
else {
|
||||
x; // B | C
|
||||
>x : Symbol(x, Decl(narrowByInstanceof.ts, 13, 13))
|
||||
}
|
||||
if (x instanceof B) {
|
||||
>x : Symbol(x, Decl(narrowByInstanceof.ts, 13, 13))
|
||||
>B : Symbol(B, Decl(narrowByInstanceof.ts, 13, 33))
|
||||
|
||||
x; // B
|
||||
>x : Symbol(x, Decl(narrowByInstanceof.ts, 13, 13))
|
||||
}
|
||||
else {
|
||||
x; // A | C
|
||||
>x : Symbol(x, Decl(narrowByInstanceof.ts, 13, 13))
|
||||
}
|
||||
if (x instanceof AB) {
|
||||
>x : Symbol(x, Decl(narrowByInstanceof.ts, 13, 13))
|
||||
>AB : Symbol(AB, Decl(narrowByInstanceof.ts, 13, 40))
|
||||
|
||||
x; // A | B
|
||||
>x : Symbol(x, Decl(narrowByInstanceof.ts, 13, 13))
|
||||
}
|
||||
else {
|
||||
x; // A | B | C
|
||||
>x : Symbol(x, Decl(narrowByInstanceof.ts, 13, 13))
|
||||
}
|
||||
}
|
||||
|
||||
function bar(target: any, Promise: any) {
|
||||
>bar : Symbol(bar, Decl(narrowByInstanceof.ts, 32, 1))
|
||||
>target : Symbol(target, Decl(narrowByInstanceof.ts, 34, 13))
|
||||
>Promise : Symbol(Promise, Decl(narrowByInstanceof.ts, 34, 25))
|
||||
|
||||
if (target instanceof Promise) {
|
||||
>target : Symbol(target, Decl(narrowByInstanceof.ts, 34, 13))
|
||||
>Promise : Symbol(Promise, Decl(narrowByInstanceof.ts, 34, 25))
|
||||
|
||||
target.__then();
|
||||
>target : Symbol(target, Decl(narrowByInstanceof.ts, 34, 13))
|
||||
}
|
||||
}
|
||||
|
||||
// Repro from #52571
|
||||
|
||||
class PersonMixin extends Function {
|
||||
>PersonMixin : Symbol(PersonMixin, Decl(narrowByInstanceof.ts, 38, 1))
|
||||
>Function : Symbol(Function, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
public check(o: any) {
|
||||
>check : Symbol(PersonMixin.check, Decl(narrowByInstanceof.ts, 42, 36))
|
||||
>o : Symbol(o, Decl(narrowByInstanceof.ts, 43, 17))
|
||||
|
||||
return typeof o === "object" && o !== null && o instanceof Person;
|
||||
>o : Symbol(o, Decl(narrowByInstanceof.ts, 43, 17))
|
||||
>o : Symbol(o, Decl(narrowByInstanceof.ts, 43, 17))
|
||||
>o : Symbol(o, Decl(narrowByInstanceof.ts, 43, 17))
|
||||
>Person : Symbol(Person, Decl(narrowByInstanceof.ts, 48, 30))
|
||||
}
|
||||
}
|
||||
|
||||
const cls = new PersonMixin();
|
||||
>cls : Symbol(cls, Decl(narrowByInstanceof.ts, 48, 5))
|
||||
>PersonMixin : Symbol(PersonMixin, Decl(narrowByInstanceof.ts, 38, 1))
|
||||
|
||||
class Person {
|
||||
>Person : Symbol(Person, Decl(narrowByInstanceof.ts, 48, 30))
|
||||
|
||||
work(): void { console.log("work") }
|
||||
>work : Symbol(Person.work, Decl(narrowByInstanceof.ts, 50, 14))
|
||||
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
|
||||
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
|
||||
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
|
||||
|
||||
sayHi(): void { console.log("Hi") }
|
||||
>sayHi : Symbol(Person.sayHi, Decl(narrowByInstanceof.ts, 51, 40))
|
||||
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
|
||||
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
|
||||
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
|
||||
}
|
||||
|
||||
class Car {
|
||||
>Car : Symbol(Car, Decl(narrowByInstanceof.ts, 53, 1))
|
||||
|
||||
sayHi(): void { console.log("Wof Wof") }
|
||||
>sayHi : Symbol(Car.sayHi, Decl(narrowByInstanceof.ts, 55, 11))
|
||||
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
|
||||
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
|
||||
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
|
||||
}
|
||||
|
||||
function test(o: Person | Car) {
|
||||
>test : Symbol(test, Decl(narrowByInstanceof.ts, 57, 1))
|
||||
>o : Symbol(o, Decl(narrowByInstanceof.ts, 59, 14))
|
||||
>Person : Symbol(Person, Decl(narrowByInstanceof.ts, 48, 30))
|
||||
>Car : Symbol(Car, Decl(narrowByInstanceof.ts, 53, 1))
|
||||
|
||||
if (o instanceof cls) {
|
||||
>o : Symbol(o, Decl(narrowByInstanceof.ts, 59, 14))
|
||||
>cls : Symbol(cls, Decl(narrowByInstanceof.ts, 48, 5))
|
||||
|
||||
console.log("Is Person");
|
||||
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
|
||||
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
|
||||
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
|
||||
|
||||
(o as Person).work()
|
||||
>(o as Person).work : Symbol(Person.work, Decl(narrowByInstanceof.ts, 50, 14))
|
||||
>o : Symbol(o, Decl(narrowByInstanceof.ts, 59, 14))
|
||||
>Person : Symbol(Person, Decl(narrowByInstanceof.ts, 48, 30))
|
||||
>work : Symbol(Person.work, Decl(narrowByInstanceof.ts, 50, 14))
|
||||
}
|
||||
else {
|
||||
console.log("Is Car")
|
||||
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
|
||||
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
|
||||
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
|
||||
|
||||
o.sayHi();
|
||||
>o.sayHi : Symbol(sayHi, Decl(narrowByInstanceof.ts, 51, 40), Decl(narrowByInstanceof.ts, 55, 11))
|
||||
>o : Symbol(o, Decl(narrowByInstanceof.ts, 59, 14))
|
||||
>sayHi : Symbol(sayHi, Decl(narrowByInstanceof.ts, 51, 40), Decl(narrowByInstanceof.ts, 55, 11))
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,190 @@
|
|||
=== tests/cases/compiler/narrowByInstanceof.ts ===
|
||||
interface A { a: string }
|
||||
>a : string
|
||||
|
||||
interface B { b: string }
|
||||
>b : string
|
||||
|
||||
interface C { c: string }
|
||||
>c : string
|
||||
|
||||
type AA = {
|
||||
>AA : { (): void; prototype: A; }
|
||||
|
||||
(): void;
|
||||
prototype: A;
|
||||
>prototype : A
|
||||
}
|
||||
|
||||
type BB = {
|
||||
>BB : new () => B
|
||||
|
||||
new(): B;
|
||||
}
|
||||
|
||||
function foo(x: A | B | C, A: AA, B: BB, AB: AA | BB) {
|
||||
>foo : (x: A | B | C, A: AA, B: BB, AB: AA | BB) => void
|
||||
>x : A | B | C
|
||||
>A : AA
|
||||
>B : BB
|
||||
>AB : AA | BB
|
||||
|
||||
if (x instanceof A) {
|
||||
>x instanceof A : boolean
|
||||
>x : A | B | C
|
||||
>A : AA
|
||||
|
||||
x; // A
|
||||
>x : A
|
||||
}
|
||||
else {
|
||||
x; // B | C
|
||||
>x : B | C
|
||||
}
|
||||
if (x instanceof B) {
|
||||
>x instanceof B : boolean
|
||||
>x : A | B | C
|
||||
>B : BB
|
||||
|
||||
x; // B
|
||||
>x : B
|
||||
}
|
||||
else {
|
||||
x; // A | C
|
||||
>x : A | C
|
||||
}
|
||||
if (x instanceof AB) {
|
||||
>x instanceof AB : boolean
|
||||
>x : A | B | C
|
||||
>AB : AA | BB
|
||||
|
||||
x; // A | B
|
||||
>x : A | B
|
||||
}
|
||||
else {
|
||||
x; // A | B | C
|
||||
>x : A | B | C
|
||||
}
|
||||
}
|
||||
|
||||
function bar(target: any, Promise: any) {
|
||||
>bar : (target: any, Promise: any) => void
|
||||
>target : any
|
||||
>Promise : any
|
||||
|
||||
if (target instanceof Promise) {
|
||||
>target instanceof Promise : boolean
|
||||
>target : any
|
||||
>Promise : any
|
||||
|
||||
target.__then();
|
||||
>target.__then() : any
|
||||
>target.__then : any
|
||||
>target : any
|
||||
>__then : any
|
||||
}
|
||||
}
|
||||
|
||||
// Repro from #52571
|
||||
|
||||
class PersonMixin extends Function {
|
||||
>PersonMixin : PersonMixin
|
||||
>Function : Function
|
||||
|
||||
public check(o: any) {
|
||||
>check : (o: any) => boolean
|
||||
>o : any
|
||||
|
||||
return typeof o === "object" && o !== null && o instanceof Person;
|
||||
>typeof o === "object" && o !== null && o instanceof Person : boolean
|
||||
>typeof o === "object" && o !== null : boolean
|
||||
>typeof o === "object" : boolean
|
||||
>typeof o : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
|
||||
>o : any
|
||||
>"object" : "object"
|
||||
>o !== null : boolean
|
||||
>o : any
|
||||
>null : null
|
||||
>o instanceof Person : boolean
|
||||
>o : any
|
||||
>Person : typeof Person
|
||||
}
|
||||
}
|
||||
|
||||
const cls = new PersonMixin();
|
||||
>cls : PersonMixin
|
||||
>new PersonMixin() : PersonMixin
|
||||
>PersonMixin : typeof PersonMixin
|
||||
|
||||
class Person {
|
||||
>Person : Person
|
||||
|
||||
work(): void { console.log("work") }
|
||||
>work : () => void
|
||||
>console.log("work") : void
|
||||
>console.log : (...data: any[]) => void
|
||||
>console : Console
|
||||
>log : (...data: any[]) => void
|
||||
>"work" : "work"
|
||||
|
||||
sayHi(): void { console.log("Hi") }
|
||||
>sayHi : () => void
|
||||
>console.log("Hi") : void
|
||||
>console.log : (...data: any[]) => void
|
||||
>console : Console
|
||||
>log : (...data: any[]) => void
|
||||
>"Hi" : "Hi"
|
||||
}
|
||||
|
||||
class Car {
|
||||
>Car : Car
|
||||
|
||||
sayHi(): void { console.log("Wof Wof") }
|
||||
>sayHi : () => void
|
||||
>console.log("Wof Wof") : void
|
||||
>console.log : (...data: any[]) => void
|
||||
>console : Console
|
||||
>log : (...data: any[]) => void
|
||||
>"Wof Wof" : "Wof Wof"
|
||||
}
|
||||
|
||||
function test(o: Person | Car) {
|
||||
>test : (o: Person | Car) => void
|
||||
>o : Person | Car
|
||||
|
||||
if (o instanceof cls) {
|
||||
>o instanceof cls : boolean
|
||||
>o : Person | Car
|
||||
>cls : PersonMixin
|
||||
|
||||
console.log("Is Person");
|
||||
>console.log("Is Person") : void
|
||||
>console.log : (...data: any[]) => void
|
||||
>console : Console
|
||||
>log : (...data: any[]) => void
|
||||
>"Is Person" : "Is Person"
|
||||
|
||||
(o as Person).work()
|
||||
>(o as Person).work() : void
|
||||
>(o as Person).work : () => void
|
||||
>(o as Person) : Person
|
||||
>o as Person : Person
|
||||
>o : Person | Car
|
||||
>work : () => void
|
||||
}
|
||||
else {
|
||||
console.log("Is Car")
|
||||
>console.log("Is Car") : void
|
||||
>console.log : (...data: any[]) => void
|
||||
>console : Console
|
||||
>log : (...data: any[]) => void
|
||||
>"Is Car" : "Is Car"
|
||||
|
||||
o.sayHi();
|
||||
>o.sayHi() : void
|
||||
>o.sayHi : (() => void) | (() => void)
|
||||
>o : Person | Car
|
||||
>sayHi : (() => void) | (() => void)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
// @strict: true
|
||||
|
||||
interface A { a: string }
|
||||
interface B { b: string }
|
||||
interface C { c: string }
|
||||
|
||||
type AA = {
|
||||
(): void;
|
||||
prototype: A;
|
||||
}
|
||||
|
||||
type BB = {
|
||||
new(): B;
|
||||
}
|
||||
|
||||
function foo(x: A | B | C, A: AA, B: BB, AB: AA | BB) {
|
||||
if (x instanceof A) {
|
||||
x; // A
|
||||
}
|
||||
else {
|
||||
x; // B | C
|
||||
}
|
||||
if (x instanceof B) {
|
||||
x; // B
|
||||
}
|
||||
else {
|
||||
x; // A | C
|
||||
}
|
||||
if (x instanceof AB) {
|
||||
x; // A | B
|
||||
}
|
||||
else {
|
||||
x; // A | B | C
|
||||
}
|
||||
}
|
||||
|
||||
function bar(target: any, Promise: any) {
|
||||
if (target instanceof Promise) {
|
||||
target.__then();
|
||||
}
|
||||
}
|
||||
|
||||
// Repro from #52571
|
||||
|
||||
class PersonMixin extends Function {
|
||||
public check(o: any) {
|
||||
return typeof o === "object" && o !== null && o instanceof Person;
|
||||
}
|
||||
}
|
||||
|
||||
const cls = new PersonMixin();
|
||||
|
||||
class Person {
|
||||
work(): void { console.log("work") }
|
||||
sayHi(): void { console.log("Hi") }
|
||||
}
|
||||
|
||||
class Car {
|
||||
sayHi(): void { console.log("Wof Wof") }
|
||||
}
|
||||
|
||||
function test(o: Person | Car) {
|
||||
if (o instanceof cls) {
|
||||
console.log("Is Person");
|
||||
(o as Person).work()
|
||||
}
|
||||
else {
|
||||
console.log("Is Car")
|
||||
o.sayHi();
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче