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

Union type inference lost in callback in else if clause #23532

Closed
rhys-vdw opened this issue Apr 19, 2018 · 5 comments
Closed

Union type inference lost in callback in else if clause #23532

rhys-vdw opened this issue Apr 19, 2018 · 5 comments
Labels
Duplicate An existing issue was already created

Comments

@rhys-vdw
Copy link
Contributor

TypeScript Version: 2.9.0-dev.20180418

Search Terms:

infer callback lost null union

Code

My attempt at a minimal reproduction - someone could probably do better:

function takeString(s: string): string {
  return s
}

const x = {
   foo: Math.random() > 0.5 ? "hello" : null
}
if (x.foo === null) {
  console.log("bar")
} else if (["hello"].some(e => e === takeString(x.foo))) { // <-- error here
  console.log("foo")
}

Expected behavior:

No error

Actual behavior:

Argument of type 'string | null' is not assignable to parameter of type 'string'.
Type 'null' is not assignable to type 'string'.

Playground Link: link

Related Issues:

@MartinJohns
Copy link
Contributor

It is working as intended, and the issue is the expression/lambda, not the else-if. The compiler has no guarantee that .some() will call your lambda immediately, so theoretically the value of x.foo could change in the meantime.

A solution would be to have an else block, then assign the correctly typed x.foo to a local const variable and pass that to the function.

#7719 (comment)

@rhys-vdw
Copy link
Contributor Author

Ah of course, thanks!

Although I should point out that this also fails when the field is readonly. So perhaps there is room for improvement here?

@MartinJohns
Copy link
Contributor

The readonly modifier is not part of the actual type of the foo property, unfortunately. The readonly modifier applies to the interface and declares that the property foo is read-only. As an unfortunate result you can just pass a readonly interface to a method accepting a mutable version and modify the object:

interface ReadonlyTest { readonly foo: string; }
interface MutableTest { foo: string; }

function mutateTest(test: MutableTest): void {
    test.foo = 'oh no!';
}

const readonlyTest: ReadonlyTest = { foo: 'bar' };
mutateTest(readonlyTest);

@RyanCavanaugh RyanCavanaugh added the Duplicate An existing issue was already created label Apr 19, 2018
@RyanCavanaugh
Copy link
Member

See #11498

@typescript-bot
Copy link
Collaborator

Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.

@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
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

4 participants