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

types of A[] || B[] and A[] ?? B[] are incorrect if A is a subtype of B #54409

Closed
Alexsey opened this issue May 26, 2023 · 7 comments
Closed
Labels
Not a Defect This behavior is one of several equally-correct options

Comments

@Alexsey
Copy link

Alexsey commented May 26, 2023

Bug Report

πŸ”Ž Search Terms

Arrays, null coalesce, OR operator, subtype reduction

πŸ•— Version & Regression Information

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

⏯ Playground Link

Playground link with relevant code

πŸ’» Code

declare const a: { x: string }[] | undefined
declare const subA: { x: string, y: number }[]
declare const notSubA: { y: number }[]

const good = a || notSubA // { x: string }[] | { y: number }[]
const bad = a || subA // { x: string }[]

πŸ™ Actual behavior

bad is { x: string }[] (type of a but without undefined)

πŸ™‚ Expected behavior

bad should be { x: string }[] | { x: string, y: number }[] (a union of a and subA without undefined).

Type of || should not depend on the relationship between types of operands

Notes

null coalesce ?? suffers from the same problem

@fatcerberus
Copy link

fatcerberus commented May 26, 2023

Subtype reduction is intended behavior. Duplicate of #46449 and others - search issues for β€œsubtype reduction”. This comes up quite often and should probably be mentioned in the FAQ at this point.

@Alexsey
Copy link
Author

Alexsey commented May 26, 2023

@fatcerberus thank you for the fast reply! I can see now it's an unfortunate design bug. I've added "subtype reduction” to the Search Terms list

@fatcerberus
Copy link

fatcerberus commented May 26, 2023

It's admittedly annoying, but not really a bug. Technically the types { x: string } | { x: string, y: number } and { x: string } are equivalent since in both cases you might have ended up with, e.g. a { x: string, y: boolean } (see #12936); you can't actually safely assume anything about y (or any property other than x for that matter) in either case.

@Alexsey
Copy link
Author

Alexsey commented May 26, 2023

@fatcerberus I'm afraid I have to disagree with your argument about the safety of the union of subtypes vs. the union of non-subtypes because your logic can be applied the same way to the non-subtype case:

type A = { a: string }
type B = { b: number }

function foo (x: A | B): string {
    if ('a' in x) {
        return x.a.toUpperCase()
    }
    return `${x.b}`
}

const runtimeCrashArg = {a: true, b: 22}

foo(runtimeCrashArg) // no error

Any union type allows such kind of type violation regardless of if the union members are bivariant or not

@fatcerberus
Copy link

fatcerberus commented May 26, 2023

Yes, in checks are known to be unsound (and narrowing based on in wasn't implemented for a long time for that reason). What I was getting at was that, if the type rules were enforced consistently and this kind of unsound narrowing wasn't possible, subtype reduction would produce fully equivalent types and is therefore not a bug in and of itself.

@fatcerberus
Copy link

Ah, this is what I was referring to: #53425 (comment)
For the record, I do agree this is a real nuisance in many cases - it's just not likely to ever be considered a bug since it aligns with the rules of the type system as designed.

@RyanCavanaugh RyanCavanaugh added the Not a Defect This behavior is one of several equally-correct options label May 26, 2023
@github-actions
Copy link

github-actions bot commented Jun 8, 2023

This issue has been marked as 'Not a Defect' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

@github-actions github-actions bot closed this as not planned Won't fix, can't repro, duplicate, stale Jun 8, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Not a Defect This behavior is one of several equally-correct options
Projects
None yet
Development

No branches or pull requests

3 participants