Typescript: Issue with unions and instanceof requiring left hand side to be type of any

Created on 15 Apr 2015  ·  14Comments  ·  Source: microsoft/TypeScript

I apologise in advance if this has been brought up somewhere else, I did do a quick search but couldn't really find it anywhere. I have the following code:

public get message() { return this._message; }
public set message(value: CString | string) {
    if (value instanceof CString) {
        this._message = isCString(value, this._message);
    } else if (typeof value === 'string') {
        this._message.setValue(value, app.languages.English);
    }
}

The typeof works fine and correctly shows value as a string within the guarded block. The following line has an error though:

if (value instanceof CString) {

The value is underlined with the following message:
"The left-hand side of an 'instanceof' expression must be of type 'any', an object type or a type parameter."

I suspect that this is because of the reason specified in this stack overflow question but it seems that this would happen so often, is there any workaround or something that can be done inside TypeScript to get around this? Technically it'll work just fine as JavaScript, it's just the intellisense/interpreter raises an error here.

Bug Fixed

Most helpful comment

@markdrake what you need is a pair of parens:

if (!(parsedJson instanceof Array)) {
     parsedJson = [parsedJson];
}

! has a higher precedence than instanceof operator. so what you were doing is (!parsedJson) instanceof Array; which is invalid.

All 14 comments

This should just work. It doesn't make sense that _every_ component of a union type should have to be an object type.

class Bar { n: number; }
class Foo { s: string; }

// Error, but shouldn't be
var x: Bar|number;
if(x instanceof Foo) { }

// No error
var y: Bar|Foo;
if(y instanceof Foo) { }

I agree, as long as at least one constituent satisfies that rule, it should be allowed.

I tried this code, and I'm actually not getting an error on the instanceof check. However, the type is not narrowing correctly in the instanceof block:

class CString {
    cStringMember: any;
}

var value: CString | string;
if (value instanceof CString) { // No error
    value.cStringMember; // Error because value has type CString | string
}
else if (typeof value === "string") {
    value = "";
}

@Anupheaus are you on master?

And on @RyanCavanaugh's example, I'm not getting any errors on master

Ok, it appears to be fixed in master.

Today we had this issue:

src/app/file.ts(26,13): error TS2358: The left-hand side of an 'instanceof' expression must be of type 'any', an object type or a type parameter.

The problem was caused by this code:

let parsedJson:any = JSON.parse(json);

if (!parsedJson instanceof Array) {
     parsedJson = [parsedJson];
}

The signature in the Json.parse object states that it returns a type any so we don't understand why the union is not possible. However the compiled file works just fine but we don't want to have false warnings in our compile process or it will become really messy with time. What can we do about it?

The version of our compiler is: message TS6029: Version 1.7.5. Thanks in advance.

+1

@markdrake what you need is a pair of parens:

if (!(parsedJson instanceof Array)) {
     parsedJson = [parsedJson];
}

! has a higher precedence than instanceof operator. so what you were doing is (!parsedJson) instanceof Array; which is invalid.

great! tanks!

@mhegazy Thank you so much

! has a higher precedence than instanceof operator.

:tired_face:

With [email protected] I'm getting

 TS2358: The left-hand side of an 'instanceof' expression must be of type 'any', an object type or a type parameter.

in a

if (this[key] instanceof Function) { }

I repro @larsenwork's issue with the following:

type CreatedOrUpdatedAt =
    { createdAt: Date | string } |
    { updatedAt: Date | string };

const datePropComp = <T extends CreatedOrUpdatedAt, K extends keyof T>(a: T, b: T, field: K) => {
    // The left-hand side of an 'instanceof' expression must be of type 'any', an object type or a type parameter.
    const dateA = a[field] instanceof Date ? a[field] : new Date(a[field]);
    const dateB = b[field] instanceof Date ? b[field] : new Date(b[field]);

    return dateA.getTime() - dateB.getTime();
};

datePropComp({ updatedAt: Date() }, { updatedAt: Date() }, 'updatedAt' )

Playground link

Was this page helpful?
0 / 5 - 0 ratings