diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d47a77a74401a..29c4a18b572c9 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -17587,6 +17587,12 @@ namespace ts { (kind & TypeFlags.NonPrimitive && isTypeAssignableTo(source, nonPrimitiveType)); } + function allTypesAssignableToKind(source: Type, kind: TypeFlags, strict?: boolean): boolean { + return source.flags & TypeFlags.Union ? + every((source as UnionType).types, subType => allTypesAssignableToKind(subType, kind, strict)) : + isTypeAssignableToKind(source, kind, strict); + } + function isConstEnumObjectType(type: Type): boolean { return getObjectFlags(type) & ObjectFlags.Anonymous && type.symbol && isConstEnumSymbol(type.symbol); } @@ -17604,7 +17610,8 @@ namespace ts { // and the right operand to be of type Any, a subtype of the 'Function' interface type, or have a call or construct signature. // The result is always of the Boolean primitive type. // NOTE: do not raise error if leftType is unknown as related error was already reported - if (!isTypeAny(leftType) && isTypeAssignableToKind(leftType, TypeFlags.Primitive)) { + if (!isTypeAny(leftType) && + allTypesAssignableToKind(leftType, TypeFlags.Primitive)) { error(left, Diagnostics.The_left_hand_side_of_an_instanceof_expression_must_be_of_type_any_an_object_type_or_a_type_parameter); } // NOTE: do not raise error if right is unknown as related error was already reported diff --git a/tests/baselines/reference/instanceofWithPrimitiveUnion.errors.txt b/tests/baselines/reference/instanceofWithPrimitiveUnion.errors.txt new file mode 100644 index 0000000000000..0172b89fecaee --- /dev/null +++ b/tests/baselines/reference/instanceofWithPrimitiveUnion.errors.txt @@ -0,0 +1,21 @@ +tests/cases/compiler/instanceofWithPrimitiveUnion.ts(2,9): error TS2358: The left-hand side of an 'instanceof' expression must be of type 'any', an object type or a type parameter. +tests/cases/compiler/instanceofWithPrimitiveUnion.ts(8,9): error TS2358: The left-hand side of an 'instanceof' expression must be of type 'any', an object type or a type parameter. + + +==== tests/cases/compiler/instanceofWithPrimitiveUnion.ts (2 errors) ==== + function test1(x: number | string) { + if (x instanceof Object) { + ~ +!!! error TS2358: The left-hand side of an 'instanceof' expression must be of type 'any', an object type or a type parameter. + x; + } + } + + function test2(x: (number | string) | number) { + if (x instanceof Object) { + ~ +!!! error TS2358: The left-hand side of an 'instanceof' expression must be of type 'any', an object type or a type parameter. + x; + } + } + \ No newline at end of file diff --git a/tests/baselines/reference/instanceofWithPrimitiveUnion.js b/tests/baselines/reference/instanceofWithPrimitiveUnion.js new file mode 100644 index 0000000000000..5510f893f18ba --- /dev/null +++ b/tests/baselines/reference/instanceofWithPrimitiveUnion.js @@ -0,0 +1,25 @@ +//// [instanceofWithPrimitiveUnion.ts] +function test1(x: number | string) { + if (x instanceof Object) { + x; + } +} + +function test2(x: (number | string) | number) { + if (x instanceof Object) { + x; + } +} + + +//// [instanceofWithPrimitiveUnion.js] +function test1(x) { + if (x instanceof Object) { + x; + } +} +function test2(x) { + if (x instanceof Object) { + x; + } +} diff --git a/tests/baselines/reference/instanceofWithPrimitiveUnion.symbols b/tests/baselines/reference/instanceofWithPrimitiveUnion.symbols new file mode 100644 index 0000000000000..f9ad5ac943caf --- /dev/null +++ b/tests/baselines/reference/instanceofWithPrimitiveUnion.symbols @@ -0,0 +1,27 @@ +=== tests/cases/compiler/instanceofWithPrimitiveUnion.ts === +function test1(x: number | string) { +>test1 : Symbol(test1, Decl(instanceofWithPrimitiveUnion.ts, 0, 0)) +>x : Symbol(x, Decl(instanceofWithPrimitiveUnion.ts, 0, 15)) + + if (x instanceof Object) { +>x : Symbol(x, Decl(instanceofWithPrimitiveUnion.ts, 0, 15)) +>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + + x; +>x : Symbol(x, Decl(instanceofWithPrimitiveUnion.ts, 0, 15)) + } +} + +function test2(x: (number | string) | number) { +>test2 : Symbol(test2, Decl(instanceofWithPrimitiveUnion.ts, 4, 1)) +>x : Symbol(x, Decl(instanceofWithPrimitiveUnion.ts, 6, 15)) + + if (x instanceof Object) { +>x : Symbol(x, Decl(instanceofWithPrimitiveUnion.ts, 6, 15)) +>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + + x; +>x : Symbol(x, Decl(instanceofWithPrimitiveUnion.ts, 6, 15)) + } +} + diff --git a/tests/baselines/reference/instanceofWithPrimitiveUnion.types b/tests/baselines/reference/instanceofWithPrimitiveUnion.types new file mode 100644 index 0000000000000..fcaba05b51f1d --- /dev/null +++ b/tests/baselines/reference/instanceofWithPrimitiveUnion.types @@ -0,0 +1,29 @@ +=== tests/cases/compiler/instanceofWithPrimitiveUnion.ts === +function test1(x: number | string) { +>test1 : (x: string | number) => void +>x : string | number + + if (x instanceof Object) { +>x instanceof Object : boolean +>x : string | number +>Object : ObjectConstructor + + x; +>x : string | number + } +} + +function test2(x: (number | string) | number) { +>test2 : (x: string | number) => void +>x : string | number + + if (x instanceof Object) { +>x instanceof Object : boolean +>x : string | number +>Object : ObjectConstructor + + x; +>x : string | number + } +} + diff --git a/tests/cases/compiler/instanceofWithPrimitiveUnion.ts b/tests/cases/compiler/instanceofWithPrimitiveUnion.ts new file mode 100644 index 0000000000000..ef70aa2602b85 --- /dev/null +++ b/tests/cases/compiler/instanceofWithPrimitiveUnion.ts @@ -0,0 +1,11 @@ +function test1(x: number | string) { + if (x instanceof Object) { + x; + } +} + +function test2(x: (number | string) | number) { + if (x instanceof Object) { + x; + } +}