mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-04-17 01:49:41 -05:00
Fix isTypeDerivedFrom to properly handle {} and intersections (#51631)
* Fix isTypeDerivedFrom to properly handle {} and intersections
* Add tests
This commit is contained in:
@@ -18759,7 +18759,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
// An object type S is considered to be derived from an object type T if
|
||||
// S is a union type and every constituent of S is derived from T,
|
||||
// T is a union type and S is derived from at least one constituent of T, or
|
||||
// S is a type variable with a base constraint that is derived from T,
|
||||
// S is an intersection type and some constituent of S is derived from T, or
|
||||
// S is a type variable with a base constraint that is derived from T, or
|
||||
// T is {} and S is an object-like type (ensuring {} is less derived than Object), or
|
||||
// T is one of the global types Object and Function and S is a subtype of T, or
|
||||
// T occurs directly or indirectly in an 'extends' clause of S.
|
||||
// Note that this check ignores type parameters and only considers the
|
||||
@@ -18767,8 +18769,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
function isTypeDerivedFrom(source: Type, target: Type): boolean {
|
||||
return source.flags & TypeFlags.Union ? every((source as UnionType).types, t => isTypeDerivedFrom(t, target)) :
|
||||
target.flags & TypeFlags.Union ? some((target as UnionType).types, t => isTypeDerivedFrom(source, t)) :
|
||||
source.flags & TypeFlags.Intersection ? some((source as IntersectionType).types, t => isTypeDerivedFrom(t, target)) :
|
||||
source.flags & TypeFlags.InstantiableNonPrimitive ? isTypeDerivedFrom(getBaseConstraintOfType(source) || unknownType, target) :
|
||||
target === globalObjectType ? !!(source.flags & (TypeFlags.Object | TypeFlags.NonPrimitive)) :
|
||||
isEmptyAnonymousObjectType(target) ? !!(source.flags & (TypeFlags.Object | TypeFlags.NonPrimitive)) :
|
||||
target === globalObjectType ? !!(source.flags & (TypeFlags.Object | TypeFlags.NonPrimitive)) && !isEmptyAnonymousObjectType(source) :
|
||||
target === globalFunctionType ? !!(source.flags & TypeFlags.Object) && isFunctionObjectType(source as ObjectType) :
|
||||
hasBaseType(source, getTargetType(target)) || (isArrayType(target) && !isReadonlyArrayType(target) && isTypeDerivedFrom(source, globalReadonlyArrayType));
|
||||
}
|
||||
|
||||
59
tests/baselines/reference/inKeywordAndIntersection.js
Normal file
59
tests/baselines/reference/inKeywordAndIntersection.js
Normal file
@@ -0,0 +1,59 @@
|
||||
//// [inKeywordAndIntersection.ts]
|
||||
class A { a = 0 }
|
||||
class B { b = 0 }
|
||||
|
||||
function f10(obj: A & { x: string } | B) {
|
||||
if (obj instanceof Object) {
|
||||
obj; // A & { x: string } | B
|
||||
}
|
||||
else {
|
||||
obj; // Error
|
||||
}
|
||||
}
|
||||
|
||||
// Repro from #50844
|
||||
|
||||
interface InstanceOne {
|
||||
one(): void
|
||||
}
|
||||
|
||||
interface InstanceTwo {
|
||||
two(): void
|
||||
}
|
||||
|
||||
const instance = {} as InstanceOne | InstanceTwo
|
||||
|
||||
const ClassOne = {} as { new(): InstanceOne } & { foo: true };
|
||||
|
||||
if (instance instanceof ClassOne) {
|
||||
instance.one();
|
||||
}
|
||||
|
||||
|
||||
//// [inKeywordAndIntersection.js]
|
||||
"use strict";
|
||||
var A = /** @class */ (function () {
|
||||
function A() {
|
||||
this.a = 0;
|
||||
}
|
||||
return A;
|
||||
}());
|
||||
var B = /** @class */ (function () {
|
||||
function B() {
|
||||
this.b = 0;
|
||||
}
|
||||
return B;
|
||||
}());
|
||||
function f10(obj) {
|
||||
if (obj instanceof Object) {
|
||||
obj; // A & { x: string } | B
|
||||
}
|
||||
else {
|
||||
obj; // Error
|
||||
}
|
||||
}
|
||||
var instance = {};
|
||||
var ClassOne = {};
|
||||
if (instance instanceof ClassOne) {
|
||||
instance.one();
|
||||
}
|
||||
65
tests/baselines/reference/inKeywordAndIntersection.symbols
Normal file
65
tests/baselines/reference/inKeywordAndIntersection.symbols
Normal file
@@ -0,0 +1,65 @@
|
||||
=== tests/cases/compiler/inKeywordAndIntersection.ts ===
|
||||
class A { a = 0 }
|
||||
>A : Symbol(A, Decl(inKeywordAndIntersection.ts, 0, 0))
|
||||
>a : Symbol(A.a, Decl(inKeywordAndIntersection.ts, 0, 9))
|
||||
|
||||
class B { b = 0 }
|
||||
>B : Symbol(B, Decl(inKeywordAndIntersection.ts, 0, 17))
|
||||
>b : Symbol(B.b, Decl(inKeywordAndIntersection.ts, 1, 9))
|
||||
|
||||
function f10(obj: A & { x: string } | B) {
|
||||
>f10 : Symbol(f10, Decl(inKeywordAndIntersection.ts, 1, 17))
|
||||
>obj : Symbol(obj, Decl(inKeywordAndIntersection.ts, 3, 13))
|
||||
>A : Symbol(A, Decl(inKeywordAndIntersection.ts, 0, 0))
|
||||
>x : Symbol(x, Decl(inKeywordAndIntersection.ts, 3, 23))
|
||||
>B : Symbol(B, Decl(inKeywordAndIntersection.ts, 0, 17))
|
||||
|
||||
if (obj instanceof Object) {
|
||||
>obj : Symbol(obj, Decl(inKeywordAndIntersection.ts, 3, 13))
|
||||
>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
obj; // A & { x: string } | B
|
||||
>obj : Symbol(obj, Decl(inKeywordAndIntersection.ts, 3, 13))
|
||||
}
|
||||
else {
|
||||
obj; // Error
|
||||
>obj : Symbol(obj, Decl(inKeywordAndIntersection.ts, 3, 13))
|
||||
}
|
||||
}
|
||||
|
||||
// Repro from #50844
|
||||
|
||||
interface InstanceOne {
|
||||
>InstanceOne : Symbol(InstanceOne, Decl(inKeywordAndIntersection.ts, 10, 1))
|
||||
|
||||
one(): void
|
||||
>one : Symbol(InstanceOne.one, Decl(inKeywordAndIntersection.ts, 14, 23))
|
||||
}
|
||||
|
||||
interface InstanceTwo {
|
||||
>InstanceTwo : Symbol(InstanceTwo, Decl(inKeywordAndIntersection.ts, 16, 1))
|
||||
|
||||
two(): void
|
||||
>two : Symbol(InstanceTwo.two, Decl(inKeywordAndIntersection.ts, 18, 23))
|
||||
}
|
||||
|
||||
const instance = {} as InstanceOne | InstanceTwo
|
||||
>instance : Symbol(instance, Decl(inKeywordAndIntersection.ts, 22, 5))
|
||||
>InstanceOne : Symbol(InstanceOne, Decl(inKeywordAndIntersection.ts, 10, 1))
|
||||
>InstanceTwo : Symbol(InstanceTwo, Decl(inKeywordAndIntersection.ts, 16, 1))
|
||||
|
||||
const ClassOne = {} as { new(): InstanceOne } & { foo: true };
|
||||
>ClassOne : Symbol(ClassOne, Decl(inKeywordAndIntersection.ts, 24, 5))
|
||||
>InstanceOne : Symbol(InstanceOne, Decl(inKeywordAndIntersection.ts, 10, 1))
|
||||
>foo : Symbol(foo, Decl(inKeywordAndIntersection.ts, 24, 49))
|
||||
|
||||
if (instance instanceof ClassOne) {
|
||||
>instance : Symbol(instance, Decl(inKeywordAndIntersection.ts, 22, 5))
|
||||
>ClassOne : Symbol(ClassOne, Decl(inKeywordAndIntersection.ts, 24, 5))
|
||||
|
||||
instance.one();
|
||||
>instance.one : Symbol(InstanceOne.one, Decl(inKeywordAndIntersection.ts, 14, 23))
|
||||
>instance : Symbol(instance, Decl(inKeywordAndIntersection.ts, 22, 5))
|
||||
>one : Symbol(InstanceOne.one, Decl(inKeywordAndIntersection.ts, 14, 23))
|
||||
}
|
||||
|
||||
66
tests/baselines/reference/inKeywordAndIntersection.types
Normal file
66
tests/baselines/reference/inKeywordAndIntersection.types
Normal file
@@ -0,0 +1,66 @@
|
||||
=== tests/cases/compiler/inKeywordAndIntersection.ts ===
|
||||
class A { a = 0 }
|
||||
>A : A
|
||||
>a : number
|
||||
>0 : 0
|
||||
|
||||
class B { b = 0 }
|
||||
>B : B
|
||||
>b : number
|
||||
>0 : 0
|
||||
|
||||
function f10(obj: A & { x: string } | B) {
|
||||
>f10 : (obj: (A & { x: string;}) | B) => void
|
||||
>obj : B | (A & { x: string; })
|
||||
>x : string
|
||||
|
||||
if (obj instanceof Object) {
|
||||
>obj instanceof Object : boolean
|
||||
>obj : B | (A & { x: string; })
|
||||
>Object : ObjectConstructor
|
||||
|
||||
obj; // A & { x: string } | B
|
||||
>obj : B | (A & { x: string; })
|
||||
}
|
||||
else {
|
||||
obj; // Error
|
||||
>obj : never
|
||||
}
|
||||
}
|
||||
|
||||
// Repro from #50844
|
||||
|
||||
interface InstanceOne {
|
||||
one(): void
|
||||
>one : () => void
|
||||
}
|
||||
|
||||
interface InstanceTwo {
|
||||
two(): void
|
||||
>two : () => void
|
||||
}
|
||||
|
||||
const instance = {} as InstanceOne | InstanceTwo
|
||||
>instance : InstanceOne | InstanceTwo
|
||||
>{} as InstanceOne | InstanceTwo : InstanceOne | InstanceTwo
|
||||
>{} : {}
|
||||
|
||||
const ClassOne = {} as { new(): InstanceOne } & { foo: true };
|
||||
>ClassOne : (new () => InstanceOne) & { foo: true; }
|
||||
>{} as { new(): InstanceOne } & { foo: true } : (new () => InstanceOne) & { foo: true; }
|
||||
>{} : {}
|
||||
>foo : true
|
||||
>true : true
|
||||
|
||||
if (instance instanceof ClassOne) {
|
||||
>instance instanceof ClassOne : boolean
|
||||
>instance : InstanceOne | InstanceTwo
|
||||
>ClassOne : (new () => InstanceOne) & { foo: true; }
|
||||
|
||||
instance.one();
|
||||
>instance.one() : void
|
||||
>instance.one : () => void
|
||||
>instance : InstanceOne
|
||||
>one : () => void
|
||||
}
|
||||
|
||||
@@ -20,4 +20,38 @@ tests/cases/compiler/inKeywordAndUnknown.ts(12,18): error TS2638: Type '{}' may
|
||||
}
|
||||
y; // {}
|
||||
}
|
||||
|
||||
// Repro from #51007
|
||||
|
||||
function isHTMLTable(table: unknown): boolean {
|
||||
return !!table && table instanceof Object && 'html' in table;
|
||||
}
|
||||
|
||||
function f1(x: unknown) {
|
||||
return x && x instanceof Object && 'a' in x;
|
||||
}
|
||||
|
||||
function f2<T>(x: T) {
|
||||
return x && x instanceof Object && 'a' in x;
|
||||
}
|
||||
|
||||
function f3(x: {}) {
|
||||
return x instanceof Object && 'a' in x;
|
||||
}
|
||||
|
||||
function f4<T extends {}>(x: T) {
|
||||
return x instanceof Object && 'a' in x;
|
||||
}
|
||||
|
||||
function f5<T>(x: T & {}) {
|
||||
return x instanceof Object && 'a' in x;
|
||||
}
|
||||
|
||||
function f6<T extends {}>(x: T & {}) {
|
||||
return x instanceof Object && 'a' in x;
|
||||
}
|
||||
|
||||
function f7<T extends object>(x: T & {}) {
|
||||
return x instanceof Object && 'a' in x;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,40 @@ function f(x: {}, y: unknown) {
|
||||
}
|
||||
y; // {}
|
||||
}
|
||||
|
||||
// Repro from #51007
|
||||
|
||||
function isHTMLTable(table: unknown): boolean {
|
||||
return !!table && table instanceof Object && 'html' in table;
|
||||
}
|
||||
|
||||
function f1(x: unknown) {
|
||||
return x && x instanceof Object && 'a' in x;
|
||||
}
|
||||
|
||||
function f2<T>(x: T) {
|
||||
return x && x instanceof Object && 'a' in x;
|
||||
}
|
||||
|
||||
function f3(x: {}) {
|
||||
return x instanceof Object && 'a' in x;
|
||||
}
|
||||
|
||||
function f4<T extends {}>(x: T) {
|
||||
return x instanceof Object && 'a' in x;
|
||||
}
|
||||
|
||||
function f5<T>(x: T & {}) {
|
||||
return x instanceof Object && 'a' in x;
|
||||
}
|
||||
|
||||
function f6<T extends {}>(x: T & {}) {
|
||||
return x instanceof Object && 'a' in x;
|
||||
}
|
||||
|
||||
function f7<T extends object>(x: T & {}) {
|
||||
return x instanceof Object && 'a' in x;
|
||||
}
|
||||
|
||||
|
||||
//// [inKeywordAndUnknown.js]
|
||||
@@ -34,3 +68,28 @@ function f(x, y) {
|
||||
}
|
||||
y; // {}
|
||||
}
|
||||
// Repro from #51007
|
||||
function isHTMLTable(table) {
|
||||
return !!table && table instanceof Object && 'html' in table;
|
||||
}
|
||||
function f1(x) {
|
||||
return x && x instanceof Object && 'a' in x;
|
||||
}
|
||||
function f2(x) {
|
||||
return x && x instanceof Object && 'a' in x;
|
||||
}
|
||||
function f3(x) {
|
||||
return x instanceof Object && 'a' in x;
|
||||
}
|
||||
function f4(x) {
|
||||
return x instanceof Object && 'a' in x;
|
||||
}
|
||||
function f5(x) {
|
||||
return x instanceof Object && 'a' in x;
|
||||
}
|
||||
function f6(x) {
|
||||
return x instanceof Object && 'a' in x;
|
||||
}
|
||||
function f7(x) {
|
||||
return x instanceof Object && 'a' in x;
|
||||
}
|
||||
|
||||
@@ -31,3 +31,98 @@ function f(x: {}, y: unknown) {
|
||||
>y : Symbol(y, Decl(inKeywordAndUnknown.ts, 2, 17))
|
||||
}
|
||||
|
||||
// Repro from #51007
|
||||
|
||||
function isHTMLTable(table: unknown): boolean {
|
||||
>isHTMLTable : Symbol(isHTMLTable, Decl(inKeywordAndUnknown.ts, 15, 1))
|
||||
>table : Symbol(table, Decl(inKeywordAndUnknown.ts, 19, 21))
|
||||
|
||||
return !!table && table instanceof Object && 'html' in table;
|
||||
>table : Symbol(table, Decl(inKeywordAndUnknown.ts, 19, 21))
|
||||
>table : Symbol(table, Decl(inKeywordAndUnknown.ts, 19, 21))
|
||||
>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
>table : Symbol(table, Decl(inKeywordAndUnknown.ts, 19, 21))
|
||||
}
|
||||
|
||||
function f1(x: unknown) {
|
||||
>f1 : Symbol(f1, Decl(inKeywordAndUnknown.ts, 21, 1))
|
||||
>x : Symbol(x, Decl(inKeywordAndUnknown.ts, 23, 12))
|
||||
|
||||
return x && x instanceof Object && 'a' in x;
|
||||
>x : Symbol(x, Decl(inKeywordAndUnknown.ts, 23, 12))
|
||||
>x : Symbol(x, Decl(inKeywordAndUnknown.ts, 23, 12))
|
||||
>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(inKeywordAndUnknown.ts, 23, 12))
|
||||
}
|
||||
|
||||
function f2<T>(x: T) {
|
||||
>f2 : Symbol(f2, Decl(inKeywordAndUnknown.ts, 25, 1))
|
||||
>T : Symbol(T, Decl(inKeywordAndUnknown.ts, 27, 12))
|
||||
>x : Symbol(x, Decl(inKeywordAndUnknown.ts, 27, 15))
|
||||
>T : Symbol(T, Decl(inKeywordAndUnknown.ts, 27, 12))
|
||||
|
||||
return x && x instanceof Object && 'a' in x;
|
||||
>x : Symbol(x, Decl(inKeywordAndUnknown.ts, 27, 15))
|
||||
>x : Symbol(x, Decl(inKeywordAndUnknown.ts, 27, 15))
|
||||
>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(inKeywordAndUnknown.ts, 27, 15))
|
||||
}
|
||||
|
||||
function f3(x: {}) {
|
||||
>f3 : Symbol(f3, Decl(inKeywordAndUnknown.ts, 29, 1))
|
||||
>x : Symbol(x, Decl(inKeywordAndUnknown.ts, 31, 12))
|
||||
|
||||
return x instanceof Object && 'a' in x;
|
||||
>x : Symbol(x, Decl(inKeywordAndUnknown.ts, 31, 12))
|
||||
>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(inKeywordAndUnknown.ts, 31, 12))
|
||||
}
|
||||
|
||||
function f4<T extends {}>(x: T) {
|
||||
>f4 : Symbol(f4, Decl(inKeywordAndUnknown.ts, 33, 1))
|
||||
>T : Symbol(T, Decl(inKeywordAndUnknown.ts, 35, 12))
|
||||
>x : Symbol(x, Decl(inKeywordAndUnknown.ts, 35, 26))
|
||||
>T : Symbol(T, Decl(inKeywordAndUnknown.ts, 35, 12))
|
||||
|
||||
return x instanceof Object && 'a' in x;
|
||||
>x : Symbol(x, Decl(inKeywordAndUnknown.ts, 35, 26))
|
||||
>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(inKeywordAndUnknown.ts, 35, 26))
|
||||
}
|
||||
|
||||
function f5<T>(x: T & {}) {
|
||||
>f5 : Symbol(f5, Decl(inKeywordAndUnknown.ts, 37, 1))
|
||||
>T : Symbol(T, Decl(inKeywordAndUnknown.ts, 39, 12))
|
||||
>x : Symbol(x, Decl(inKeywordAndUnknown.ts, 39, 15))
|
||||
>T : Symbol(T, Decl(inKeywordAndUnknown.ts, 39, 12))
|
||||
|
||||
return x instanceof Object && 'a' in x;
|
||||
>x : Symbol(x, Decl(inKeywordAndUnknown.ts, 39, 15))
|
||||
>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(inKeywordAndUnknown.ts, 39, 15))
|
||||
}
|
||||
|
||||
function f6<T extends {}>(x: T & {}) {
|
||||
>f6 : Symbol(f6, Decl(inKeywordAndUnknown.ts, 41, 1))
|
||||
>T : Symbol(T, Decl(inKeywordAndUnknown.ts, 43, 12))
|
||||
>x : Symbol(x, Decl(inKeywordAndUnknown.ts, 43, 26))
|
||||
>T : Symbol(T, Decl(inKeywordAndUnknown.ts, 43, 12))
|
||||
|
||||
return x instanceof Object && 'a' in x;
|
||||
>x : Symbol(x, Decl(inKeywordAndUnknown.ts, 43, 26))
|
||||
>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(inKeywordAndUnknown.ts, 43, 26))
|
||||
}
|
||||
|
||||
function f7<T extends object>(x: T & {}) {
|
||||
>f7 : Symbol(f7, Decl(inKeywordAndUnknown.ts, 45, 1))
|
||||
>T : Symbol(T, Decl(inKeywordAndUnknown.ts, 47, 12))
|
||||
>x : Symbol(x, Decl(inKeywordAndUnknown.ts, 47, 30))
|
||||
>T : Symbol(T, Decl(inKeywordAndUnknown.ts, 47, 12))
|
||||
|
||||
return x instanceof Object && 'a' in x;
|
||||
>x : Symbol(x, Decl(inKeywordAndUnknown.ts, 47, 30))
|
||||
>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(inKeywordAndUnknown.ts, 47, 30))
|
||||
}
|
||||
|
||||
|
||||
@@ -40,3 +40,125 @@ function f(x: {}, y: unknown) {
|
||||
>y : Record<"a", unknown>
|
||||
}
|
||||
|
||||
// Repro from #51007
|
||||
|
||||
function isHTMLTable(table: unknown): boolean {
|
||||
>isHTMLTable : (table: unknown) => boolean
|
||||
>table : unknown
|
||||
|
||||
return !!table && table instanceof Object && 'html' in table;
|
||||
>!!table && table instanceof Object && 'html' in table : boolean
|
||||
>!!table && table instanceof Object : boolean
|
||||
>!!table : boolean
|
||||
>!table : boolean
|
||||
>table : unknown
|
||||
>table instanceof Object : boolean
|
||||
>table : {}
|
||||
>Object : ObjectConstructor
|
||||
>'html' in table : boolean
|
||||
>'html' : "html"
|
||||
>table : Object
|
||||
}
|
||||
|
||||
function f1(x: unknown) {
|
||||
>f1 : (x: unknown) => unknown
|
||||
>x : unknown
|
||||
|
||||
return x && x instanceof Object && 'a' in x;
|
||||
>x && x instanceof Object && 'a' in x : unknown
|
||||
>x && x instanceof Object : unknown
|
||||
>x : unknown
|
||||
>x instanceof Object : boolean
|
||||
>x : {}
|
||||
>Object : ObjectConstructor
|
||||
>'a' in x : boolean
|
||||
>'a' : "a"
|
||||
>x : Object
|
||||
}
|
||||
|
||||
function f2<T>(x: T) {
|
||||
>f2 : <T>(x: T) => boolean
|
||||
>x : T
|
||||
|
||||
return x && x instanceof Object && 'a' in x;
|
||||
>x && x instanceof Object && 'a' in x : boolean
|
||||
>x && x instanceof Object : boolean
|
||||
>x : T
|
||||
>x instanceof Object : boolean
|
||||
>x : NonNullable<T>
|
||||
>Object : ObjectConstructor
|
||||
>'a' in x : boolean
|
||||
>'a' : "a"
|
||||
>x : T & Object
|
||||
}
|
||||
|
||||
function f3(x: {}) {
|
||||
>f3 : (x: {}) => boolean
|
||||
>x : {}
|
||||
|
||||
return x instanceof Object && 'a' in x;
|
||||
>x instanceof Object && 'a' in x : boolean
|
||||
>x instanceof Object : boolean
|
||||
>x : {}
|
||||
>Object : ObjectConstructor
|
||||
>'a' in x : boolean
|
||||
>'a' : "a"
|
||||
>x : Object
|
||||
}
|
||||
|
||||
function f4<T extends {}>(x: T) {
|
||||
>f4 : <T extends {}>(x: T) => boolean
|
||||
>x : T
|
||||
|
||||
return x instanceof Object && 'a' in x;
|
||||
>x instanceof Object && 'a' in x : boolean
|
||||
>x instanceof Object : boolean
|
||||
>x : T
|
||||
>Object : ObjectConstructor
|
||||
>'a' in x : boolean
|
||||
>'a' : "a"
|
||||
>x : T & Object
|
||||
}
|
||||
|
||||
function f5<T>(x: T & {}) {
|
||||
>f5 : <T>(x: T & {}) => boolean
|
||||
>x : T & {}
|
||||
|
||||
return x instanceof Object && 'a' in x;
|
||||
>x instanceof Object && 'a' in x : boolean
|
||||
>x instanceof Object : boolean
|
||||
>x : T & {}
|
||||
>Object : ObjectConstructor
|
||||
>'a' in x : boolean
|
||||
>'a' : "a"
|
||||
>x : T & Object
|
||||
}
|
||||
|
||||
function f6<T extends {}>(x: T & {}) {
|
||||
>f6 : <T extends {}>(x: T & {}) => boolean
|
||||
>x : T & {}
|
||||
|
||||
return x instanceof Object && 'a' in x;
|
||||
>x instanceof Object && 'a' in x : boolean
|
||||
>x instanceof Object : boolean
|
||||
>x : T & {}
|
||||
>Object : ObjectConstructor
|
||||
>'a' in x : boolean
|
||||
>'a' : "a"
|
||||
>x : T & Object
|
||||
}
|
||||
|
||||
function f7<T extends object>(x: T & {}) {
|
||||
>f7 : <T extends object>(x: T & {}) => boolean
|
||||
>x : T & {}
|
||||
|
||||
return x instanceof Object && 'a' in x;
|
||||
>x instanceof Object && 'a' in x : boolean
|
||||
>x instanceof Object : boolean
|
||||
>x : T & {}
|
||||
>Object : ObjectConstructor
|
||||
>'a' in x : boolean
|
||||
>'a' : "a"
|
||||
>x : T & {}
|
||||
}
|
||||
|
||||
|
||||
31
tests/cases/compiler/inKeywordAndIntersection.ts
Normal file
31
tests/cases/compiler/inKeywordAndIntersection.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
// @strict: true
|
||||
|
||||
class A { a = 0 }
|
||||
class B { b = 0 }
|
||||
|
||||
function f10(obj: A & { x: string } | B) {
|
||||
if (obj instanceof Object) {
|
||||
obj; // A & { x: string } | B
|
||||
}
|
||||
else {
|
||||
obj; // Error
|
||||
}
|
||||
}
|
||||
|
||||
// Repro from #50844
|
||||
|
||||
interface InstanceOne {
|
||||
one(): void
|
||||
}
|
||||
|
||||
interface InstanceTwo {
|
||||
two(): void
|
||||
}
|
||||
|
||||
const instance = {} as InstanceOne | InstanceTwo
|
||||
|
||||
const ClassOne = {} as { new(): InstanceOne } & { foo: true };
|
||||
|
||||
if (instance instanceof ClassOne) {
|
||||
instance.one();
|
||||
}
|
||||
@@ -16,3 +16,37 @@ function f(x: {}, y: unknown) {
|
||||
}
|
||||
y; // {}
|
||||
}
|
||||
|
||||
// Repro from #51007
|
||||
|
||||
function isHTMLTable(table: unknown): boolean {
|
||||
return !!table && table instanceof Object && 'html' in table;
|
||||
}
|
||||
|
||||
function f1(x: unknown) {
|
||||
return x && x instanceof Object && 'a' in x;
|
||||
}
|
||||
|
||||
function f2<T>(x: T) {
|
||||
return x && x instanceof Object && 'a' in x;
|
||||
}
|
||||
|
||||
function f3(x: {}) {
|
||||
return x instanceof Object && 'a' in x;
|
||||
}
|
||||
|
||||
function f4<T extends {}>(x: T) {
|
||||
return x instanceof Object && 'a' in x;
|
||||
}
|
||||
|
||||
function f5<T>(x: T & {}) {
|
||||
return x instanceof Object && 'a' in x;
|
||||
}
|
||||
|
||||
function f6<T extends {}>(x: T & {}) {
|
||||
return x instanceof Object && 'a' in x;
|
||||
}
|
||||
|
||||
function f7<T extends object>(x: T & {}) {
|
||||
return x instanceof Object && 'a' in x;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user