Skip to content

why doesn't this work? #6538

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
zpdDG4gta8XKpMCd opened this issue Jan 19, 2016 · 6 comments
Closed

why doesn't this work? #6538

zpdDG4gta8XKpMCd opened this issue Jan 19, 2016 · 6 comments
Labels
Question An issue which isn't directly actionable in code

Comments

@zpdDG4gta8XKpMCd
Copy link

interface X { x: number; }
interface Y { y: number; }
interface Named { name: string; }
interface Z { z: number; }
type W = (X | Y) & Named | Z;
function isNamed(w: W): w is Named {
    return undefined;
}

image

@RyanCavanaugh
Copy link
Member

I tried to write an explanation, but the explanation was the same as the error message.

Are you asking why type predicates must be assignable to their corresponding parameter types? Or something else?

@RyanCavanaugh RyanCavanaugh added the Question An issue which isn't directly actionable in code label Jan 19, 2016
@DanielRosenwasser
Copy link
Member

Here's a simplified example:

interface Animal {
    animal;
}

interface Dog extends Animal {
    dog;
}

interface Car {
    car;
}

let thing: Dog | Car;

// Get a similar error here
function isAnimal(x: Car | Dog): x is Animal {
    return "animal" in x;
}

Basically we're trying to tell you that it's nonsensical to say x is Animal because Animal is more general than Dog. If you're getting a Dog as your input, you should say x is Dog.

That said, it sounds like we should have a better error message here. See #6540.

@sandersn
Copy link
Member

[Assuming that the question is why the assignability check failed.]

The error message actually doesn't make it clear that the compiler tried to assign Named to both Z and (X | Y) & Named. It reports only that Named isn't assignable to Z. The compiler also tried to assign Named to (X | Y) & Named, but that also failed, because Named is not assignable to (X | Y).

I wouldn't call @DanielRosenwasser's example simplified so much as shifting the root cause of assignability failure from intersection (& (X | Y)) to subclassing (extends Animal).

@zpdDG4gta8XKpMCd
Copy link
Author

@RyanCavanaugh I hear you, give me the number of the issue that deals with it.

Isn't (X | Y) & Named === X & Named | Y & Named?

If so how is (X | Y) & Named | Z this different from Named | Z which works?

interface Named { name: string; }
interface Z { z : number; }
type W = Named | Z;
function isNamed(w: W): w is Named { // <-- no problemos
    return undefined;
}

@sandersn
Copy link
Member

The difference is the assignability of intersection versus union:

declare var n: Named;
let xnamed: X & Named = n;

Named is not assignable to X & Named because it doesn't have X's properties.

@zpdDG4gta8XKpMCd
Copy link
Author

but from a common sense stand point situation where I ask whether w: X & Named | Z can be Named is normal, isn't it? If I can come up with a runtime test that asserts it why is it a crime from assignability standpoint? It looks like assignability checkings aren't the proper vehicles for type guards.

@microsoft microsoft locked and limited conversation to collaborators Jun 19, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Question An issue which isn't directly actionable in code
Projects
None yet
Development

No branches or pull requests

4 participants