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 can allow required properties of a member type to be missing #55548

Closed
AndrewFerr opened this issue Aug 28, 2023 · 5 comments
Closed
Labels
Duplicate An existing issue was already created

Comments

@AndrewFerr
Copy link

πŸ”Ž Search Terms

union member in partial

πŸ•— Version & Regression Information

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

⏯ Playground Link

https://www.typescriptlang.org/play?ts=5.3.0-dev.20230828#code/JYOwLgpgTgZghgYwgAgCoAU5TARmQbwChkTk4AuZEAVwFsAjaAbmNPspoecIF9DDQkWIhQYsYAEwFWJBBzqMoLUsgAm8rkt78EAexABnMMgAO4nAH04IVRbPZgcADZ3xUgLzSVFZDgA0MsjsyBIBKnLIAMwBfIQw1CAIYMD6yDAWYtg4APJQEgAUAB6UmbgAPqUSAJRepMAwyPkA5AhNyKDIhTVEKiqFAHSqyABUnhLKpHzh+ga6ThD9TroA5kVVLHzppTl5+fa4VjauDs7Hkuv8gtDwSGgAQrpgABbIEIWQNgZomFl+324EPhgACeJlEP1wuQez2Qnm2yDK90eTxY8USyVSWwhO2hTyKJWxUOR3UC9UaLTaHS6tV6nUGIzGExIU1IekMcwWS1WXQ2cQyhKguL25kOtn2jhc+2qLEIILB-yyuQAkuBoAYIEkUiBYQrcAjGvCAGS66VxBKazH88zK1VQdUWkD43U7FVCe0YkAklRk5qtdra6k9Wl0oajEJM5As2QzDmLFZrXlY61QV1qjUe4VZUVnCVnU2y0Hg8wAQRsAFk4MDGBCPM7kMb8pV9fgeBc0Q60lasqXVBWqxAa07tj2+9W3F66g1fZSAxPaQNQ4zAlHkGzZvM49yLpsu7gR5Wx9gCvtLNYxeJc1L1kA

πŸ’» Code

interface TPart1 {
    a: number;
    b: number;
}

interface TPart2 {
    c: number;
    d: number;
}

const part1_and_partial_part2 = {
    a: 1,
    b: 2,
    c: 3,
}

function f_TPart1Or2(x: TPart1|TPart2) {
    if ('c' in x) {
        x.d *= 2;
    }
    console.log(x);
}
f_TPart1Or2(part1_and_partial_part2);

interface TBoth extends TPart1, TPart2 {}
type TPart1OrBoth = TPart1 | TBoth;
function f_TPart1OrBoth(x: TPart1OrBoth) {
    if ('c' in x) {
        x.d *= 2;
    }
    console.log(x);
}
f_TPart1OrBoth(part1_and_partial_part2);

type TPart1OrIntersection = TPart1 | (TPart1 & TPart2);
function f_TPart1OrIntersection(x: TPart1OrIntersection) {
    if ('c' in x) {
        x.d *= 2;
    }
    console.log(x);
}
f_TPart1OrIntersection(part1_and_partial_part2);

type TPart1AndMaybePart2 = TPart1 & (TPart2 | {});
function f_TPart1AndMaybePart2(x: TPart1AndMaybePart2) {
    if ('c' in x) {
        x.d *= 2;
    }
    console.log(x);
}
f_TPart1AndMaybePart2(part1_and_partial_part2);

πŸ™ Actual behavior

No error is caught by static analysis, and each function is allowed to access & modify x.d despite it not existing in the value of x that they are given.

πŸ™‚ Expected behavior

A "not assignable to type" error should be raised when trying to pass either function an object that partially implements TPart2, even if that object fully implements TPart1.

Alternatively, the presence of any property of TPart2 on the object shouldn't assume the presence of all other properties of TPart2 on that object.

Additional information about the issue

When an object fully satisfies a particular interface/type and partially satisfies another, that object is considered to satisfy the union of the fully-satisfied type & the partially-satisfied one.

However, this breaks the assumption that if the object has any property of the partially-satisfied interface/type, it must have all of them.

A way around this is to distinguish types by adding tag properties to them Γ  la discriminated unions, but this requires runtime-visible changes to objects that could perhaps be avoided by stricter static analysis.

@MartinJohns
Copy link
Contributor

The in operator is intentionally unsound.

@jcalz
Copy link
Contributor

jcalz commented Aug 28, 2023

See #34975

@andrewbranch
Copy link
Member

Duplicate of #34975

@andrewbranch andrewbranch marked this as a duplicate of #34975 Aug 28, 2023
@andrewbranch andrewbranch added the Duplicate An existing issue was already created label Aug 28, 2023
@fatcerberus
Copy link

A "not assignable to type" error should be raised when trying to pass either function an object that partially implements TPart2, even if that object fully implements TPart1.

With respect to this bit specifically: #12936

@typescript-bot
Copy link
Collaborator

This issue has been marked as "Duplicate" and has seen no recent activity. It has been automatically closed for house-keeping purposes.

@typescript-bot typescript-bot closed this as not planned Won't fix, can't repro, duplicate, stale Sep 1, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

6 participants