Skip to content

Issue with unions and instanceof requiring left hand side to be type of any #2775

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Anupheaus opened this issue Apr 15, 2015 · 14 comments
Closed
Labels
Bug A bug in TypeScript Fixed A PR has been merged for this issue

Comments

@Anupheaus
Copy link

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.

@RyanCavanaugh RyanCavanaugh added the Bug A bug in TypeScript label Apr 16, 2015
@RyanCavanaugh
Copy link
Member

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) { }

@JsonFreeman
Copy link
Contributor

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

@JsonFreeman
Copy link
Contributor

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?

@JsonFreeman
Copy link
Contributor

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

@JsonFreeman
Copy link
Contributor

Ok, it appears to be fixed in master.

@RyanCavanaugh RyanCavanaugh added the Fixed A PR has been merged for this issue label Apr 17, 2015
@markdrake
Copy link

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.

@rrgarciach
Copy link

+1

@mhegazy
Copy link
Contributor

mhegazy commented Jan 9, 2016

@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.

@rrgarciach
Copy link

great! tanks!

@markdrake
Copy link

@mhegazy Thank you so much

@DanielRosenwasser
Copy link
Member

! has a higher precedence than instanceof operator.

😫

@larsenwork
Copy link

larsenwork commented Aug 21, 2017

With typescript@2.5.1 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) { }

@yangchristian
Copy link

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

@mhegazy
Copy link
Contributor

mhegazy commented Oct 18, 2017

Filed #19298 to track that.

@microsoft microsoft locked and limited conversation to collaborators Jul 31, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Bug A bug in TypeScript Fixed A PR has been merged for this issue
Projects
None yet
Development

No branches or pull requests

9 participants