Skip to content
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

instanceof / structural typing issue #15585

Closed
mikelehen opened this issue May 4, 2017 · 1 comment · Fixed by #19671
Closed

instanceof / structural typing issue #15585

mikelehen opened this issue May 4, 2017 · 1 comment · Fixed by #19671
Assignees
Labels
Fixed A PR has been merged for this issue

Comments

@mikelehen
Copy link

mikelehen commented May 4, 2017

This may be a dupe of #11664 though that deals with a type union and this is purely inheritance.

TypeScript Version: 2.3.2

Code

abstract class Value {
  readonly valueType: number;
  abstract value(): any;
}

class NullValue extends Value {
  valueType = 0;

  value(): any {
    return null;
  }
}

class NumberValue extends Value {
  valueType = 1;

  constructor(readonly num: number) { super(); }

  value(): any {
    return this.num;
  }
}

function process(node: Value) {
  if (node instanceof NullValue) {
    console.log('Null!')
  } else if (node instanceof NumberValue) {
    // Produces: TS2339: Property 'num' does not exist on type 'never'.
    console.log('NumberValue', node.num);
  }
}

Expected behavior: No errors.

Actual behavior: Error:

test.ts(29,37): error TS2339: Property 'num' does not exist on type 'never'.

I can "solve" the issue by adding a dummy readonly foo = null; field to the NullValue class.

@aluanhaddad
Copy link
Contributor

aluanhaddad commented May 17, 2017

The issue here is that, as you suggest, NullValue is a structural supertype of NumberValue. Since you test for NullValue first, the typechecker concludes that that node cannot be a NumberValue since it did not meet the requirements to be a value of its supertype.

By the same token, the following assignment is legal

const x : NullValue = new NumberValue(1);

However, in the case of the process function above, if one just reverses the order of the checks like so

function process(node: Value) {
  if (node instanceof NumberValue) {
    console.log('NumberValue', node.num);
  } else if (node instanceof NullValue) {
    console.log('Null!');
  }
}

there is no longer an error.

@RyanCavanaugh RyanCavanaugh added the Needs Investigation This issue needs a team member to investigate its status. label May 24, 2017
@mhegazy mhegazy added Fixed A PR has been merged for this issue and removed Needs Investigation This issue needs a team member to investigate its status. labels Nov 2, 2017
@mhegazy mhegazy added this to the TypeScript 2.7 milestone Nov 2, 2017
@microsoft microsoft locked and limited conversation to collaborators Jun 14, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Fixed A PR has been merged for this issue
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants