Skip to content

Using <X>() => X extends V ? 1 : 2 ignores readonly in object properties of V when called via a type alias #55618

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
sbr61 opened this issue Sep 3, 2023 · 3 comments
Labels
Duplicate An existing issue was already created

Comments

@sbr61
Copy link

sbr61 commented Sep 3, 2023

🔎 Search Terms

readonly property ignored in type alias

🕗 Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about Common "Bugs" That Aren't Bugs
  • I tested all playground versions between 3.9.7 and 5.2.2 plus Nightly

⏯ Playground Link

https://www.typescriptlang.org/play?ts=5.2.2#code/PQKgUABBAcCc0QLQQJIDsDGAbArgEwFMBnSJRci0gIwE8I0cssIAKAAQGsa0CAzHDgEoIAYgIBDInRHiATrPE0wpEaogBFHMQAuASwD2aZVBQBbAA5YCpgmm0RtACwIQAUuIBu4gMoZZu83sAAwBBeUUAOl1MXEIiIIh+TD1DCGiHZwcacxcpIm1rCIgQrJyHcQ5iDJdtAHd9CDkAcxwbOyIigBVM-Rxtcz6IIkderDwIKhdxCf19K3E0CCDtWS0E-Vkl3nEsIgIgiOMIADENiAIAD3ELKwAuI6DH7RIobWyXXSIABV0mOQBZWwQAC8qBi+GIAB4ANoAcgA0nIiLCADQQWEAUSIujwn10qPRAHVrjgcATYd4FtoFuJYQBdNGwgAiBlhAD4IMBgOcLjkMAVxtoGpMtjs9kFSI8JaQOQA1XQEWoQVIAcV02gAEjgqLcII5tP0iLcuc8MI4IgArDobJrAODQMAgYDKUAQAD6Hs9Xs9EAAmr1NgBhfSECAagiyFze6MeiBOl3c7y1dVmiYEOoEIFefxUogTOiSbFNNDRJrVBw6AjjbO6Kl6iMEQ5vMrobAQoiQzo8gpoPB5yPiPCGLAFtA0aEMiAAVQ5wNIrdixAATJ20TOoJzufVZBw87VnIscNi0GWF+2AMxos9xc9UK-guIAFlIG9fb-fXKGI0Y4zFDW3HAQMmThgm2cRLo0vagYuRBLneL7vohr6flAVCDLoxYbFUA5DmgI5pIs+hUBaBD8hA5iyPoOSyHoxDKM2LjXsQACMnbdrYfYQDhw6juOk7rnOUBTuxvZ5p00IMKYkyyHSEAAPwOKsLi6tsuwuJ+Q5VGg+j2EQcweDUjifBAZo7FgCxNAQCYQN0xAuDWuZfqMv5MEM+mGS4plMLYln3GADEQMGFhyBGkKyrOECQgAGmyLDCMCHJRSJnGyvJEDMRAupLvR7yBfowWRrIYQKDQbGXD2nHcXhvEThFADepDQvCBEQJUND6LwNl0rqQXmCFsidk1dJsmAAC+OUtg+y5lRcFX9hIuH4QsfFrrOpC9f1kLruVHF5hthXFYonZshJrTSbJCkrFomWJGKVn+blTGwVQM1zVxC08ZBK3TmtJhTUQrH7RGh2lZ0bJokDA0ziND2TWBxDnq9u3vYOn3LROq0gghLDRbF8WJclebCQpGVZcIO2iXlBXA+EoMnZJ51pVdym3WpE2Mf9t5I5TVVLWOGM-Vjf3wwDkKQyDx1orjcUggTFOccT6U3UuMMBU9j7c5VH3VV9AsCaQOMxTLCUQEl8tE2lpMQEu5OzcjDWvk1LVtR1XW6tL+Om4TNlDZbyukKNp1SRGF2KddKl3ezNkZaCT0wnVjS6rCISwhAo2TgnvMFknKdpxyn4BcziRnE9S7AHBaJobp35jGmrN7KwkjF5sT3nsAt7AI+giwy4nQQbH-3xyji3Z+iufp2iCfiDnqejfn3KF0pzfQe2ZcVxMgzDM5deqQ3LBN7wJec+3VCd93YCujG0Y2TogWSFUV-enGzq6BYGz2AFCcYgAjjgOxohiXkpF7CjUSJRUw6I2AMUQF5KwJ5iDAD6L8ZEUcMD3zzKCaEpBAF8m0JCH+f8sCQjjnCREshkSMixDiPE5JiSmFJOSSkdgaT0kZGQ5E4Mw4EDZODbBQD+T4N-jsYhg9SFInJFQ3E2JaEkjJIyJh1I0C0knMyVknDd7cN4VAHBwDBGEJESLGEzE0RLjRJeCAABWNEAA2NEAB2ScdjOHMx4SiPhuC9HCJIcY62Zi0RWIgLYiADi0SPnUXdVx7jdEEK8aInxpiIDnknCrNELitEQB0QImJRDvEmLMZOZizilKRO0fwvB2SDEwXjhPCAU8Z55zRBokpGSymeJyaIqgsx5hoDyYk-xNj7GTiaY0iJ6TMnlKEe0wx0Jma9PMQEoJISZhzAkGgcJalmnjLaZU9sMINFzP6YEwZIyNmpOKWM1pFSSF1LHrPDOw80b1LnicvYmzLmTJ2XEIeWdE63LTvc6efznn100W40pHirlxIKRAAAPtbdZryLkQo+d42F1sCkItBVErJKLREMCYJOHAvY+DRCrJit5yL9EkKJYQXgpK8CTnxVgclvC6QuhAO6R+Ppjg4Bos4TY3gCjmDzFyn08ZQAyggN4RwIUIDtV5W5XAKQ0BGj1AaYVxpgCmnNFaCINo7TwGAAsIgtQIySvlIqRVSDDCqv1IaTV2rLTWlkLae0wA9JKoMCqyV-wsKBRld5eBtr1VGhNEQM0Tq9UusdM6IAA

💻 Code

// Switch between variants by assigning the tested variant here.
type Includes<T extends readonly any[], U> =  Includes2<T, U> // Includes2 fails, Includes3 works

type Comparer<V> = <X>() => X extends V ? 1 : 2

type ComparerArray<T extends readonly any[]> = {
  [K in keyof T]: Comparer<T[K]>
}

type Includes2<T extends readonly any[], U> =
  Comparer<U> extends ComparerArray<T>[number] ? true : false

type Includes3<T extends readonly any[], U> =
    (<X>() => X extends U ? 1 : 2) extends ComparerArray<T>[number] ? true : false

type T1 = Includes<[{ a: 'A' }], { readonly a: 'A' }> // type true for Includes2, but should be false (as for Includes3)
type T2 = Includes<[{ readonly a: 'A' }], { a: 'A' }> // type true for Includes2, but should be false (as for Includes3)

🙁 Actual behavior

When the type alias Comparer<V> is called from the type alias Includes2, it ignores readonly attributes of object properties in the type comparison. Both T1 and T2 result in the type true.

🙂 Expected behavior

When the type alias Comparer<V> is called from the type alias Includes2, it should not ignore readonly attributes of object type properties in the type comparison. Both T1 and T2 should result in the type false.

That is, Includes2 should behave exactly as Includes3, which is identical to Includes2 except that it has inlined the call to Comparer<V> and does not ignore readonly attributes of object type properties. (Here, T1 and T2 both result in the type false.)

Additional information about the issue

For reproducing the problem in the playground, please activate @Type Challenges/plugin.

For an explanation of the sample code see the solution for the Includes type challenge here:
898 - Includes - Non-recursive solution using array union with explanations.

@whzx5byb
Copy link

whzx5byb commented Sep 3, 2023

This is essentially a duplicate of #48070.

Also note that { readonly a: 'A' } is assignable to { a: 'A' } at the moment. This is unsound and has been discussed for years (#13002 | #13347) but still not been solved.

@fatcerberus
Copy link

fatcerberus commented Sep 3, 2023

Rationale for why readonly object types are assignable to non-readonly ones: #6532 (comment)

That was a 100% intentional design decision (note @ahejlsberg’s implying the original implementation actually did prevent the assignment) and seems unlikely to change, at least not before we also get mutable modifiers too.

@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 8, 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

5 participants