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

Narrowring a readonly class with instanceof of does not work on the else branch #58543

Closed
terenc3 opened this issue May 15, 2024 · 4 comments
Closed
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug

Comments

@terenc3
Copy link

terenc3 commented May 15, 2024

πŸ”Ž Search Terms

instanceof narrowing readonly generic

πŸ•— Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about Readonly and instanceof Narrowing

⏯ Playground Link

https://www.typescriptlang.org/play/?ts=5.5.0-dev.20240515#code/MYGwhgzhAECC0G8CwAoa7oAsCmIQHsAuaCAFwCcBLAOwHNoBeaAIhz32dQF9VUbTs5AGZhg2aACFEqDNADu+ciAAmxMlTrdeKIQFdqwUpXzVo1MOXL45ACnwAjAFbEAStjDKTIAJ4AeWAB80AA+kgCUahQ09MhoGJRC0HZO0DRkYAbY+ImwYdJxsujk2KS65KYOjgB0bAQA3DIYPAXQxaXl0JVVCkrKDShcQA

πŸ’» Code

class A {
    hello: string = "hello"
}

interface B {
    world: string
}

function narrow(obj: Readonly<A> | B): string {
    if (obj instanceof A) {
        return obj.hello;
    }
    return obj.world;
}

πŸ™ Actual behavior

TypeScript is not narrowing the type of obj to B and therefore reports a property does not exist

πŸ™‚ Expected behavior

The same narrowring which will happen without the Readonly utitlity type

Additional information about the issue

No response

@whzx5byb
Copy link

whzx5byb commented May 15, 2024

The same narrowing which will happen without the Readonly utitlity type

Please note that this behavior is unsound. In theory, "not instanceof" should never narrow the type, since ts uses structural typing, and something which is not an instance of A can still be of type A in structure. Here's an example and the explanation by a team member.

@RyanCavanaugh RyanCavanaugh added the Working as Intended The behavior described is the intended behavior; this is not a bug label Jun 6, 2024
@RyanCavanaugh
Copy link
Member

This analysis is done structurually and A is a subtype of Readonly<A>, so knowing that obj isn't an A doesn't tell you that it's a B.

By analogy, if have something that is an Animal (Readonly<A>) or House (B), knowing that it's not a Cat (A) is not enough information to determine that it's a House.

@terenc3
Copy link
Author

terenc3 commented Jun 7, 2024

Interesting in my head it was the other way around that Readonly would be subtype of A and then i thought that it would be possible for TS to figure that out. Thanks for the clarification πŸ‘

@terenc3 terenc3 closed this as completed Jun 7, 2024
@RyanCavanaugh
Copy link
Member

Interesting in my head it was the other way around that Readonly would be subtype of A

This is definitely one of those things that feels true but isn't

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug
Projects
None yet
Development

No branches or pull requests

3 participants