-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Impossible intersection is supposedly never but any can still be assigned to it #53027
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
Comments
Is this behavior observable in a way that matters? |
Two problems I know of that seem to be caused by this. First, it means assigning to the quasi-never type const n3: AB = {
// @ts-expect-error: Type 'number' is not assignable to type 'never'.
a: 3,
} Second, it means that type DistributedOmit<T, K extends keyof any> = T extends any ? Omit<T, K> : never
// @ts-expect-error: Type '{}' is not assignable to type 'never'.
const n4: DistributedOmit<never, "bogus"> = {}
// allowed
const n5: DistributedOmit<AB, "bogus"> = {} (To be clear, these are all simplified from something I ran into in real code.) Full playground here. |
The presented issue was that you don't want |
Sure, I guess that was intended as the simplest example of "this type is supposedly never but is not in fact equivalent to never". Apologies if I misunderstood how these are related; if it's more useful, I'm happy to make a new issue framed around those examples. |
Yeah, the exact manifestation / what you care about matters. These are all orthogonally addressable, in theory. The PR notes that this is a consequence of the reduction being deferred:
I'm not sure if there are any cures on the table which are better than the disease here. Basically, not all of these can be true at once:
so we have to park the inconsistency somewhere. It's extremely rare to see a zero-order intersection that reduces to IMO probably the most convincing example that something is wrong is something like this: // x is effectively { [s: string]: never }
type X = Omit<A & B, "nada">;
const x: X = { }; // Allowed initialization, maaaaybe ok per definition of X?
const s: string = x.anything; // Allowed property access, sad
console.log(s.toLowerCase()); // Crash, sad. but the initialization of // @ts-expect-error: Type '{}' is not assignable to type 'never'.
const n4: DistributedOmit<never, "bogus"> = {} which is sort of a niche problem. |
Got it -- I don't know that I understand all the details of the implementation issues here but I see why it's useful for you to know which inconsistencies are the most relevant. In the case where this came up for me, I think the most confusing thing is that the errors are on the fields rather than the whole object? Definitely the fact that
The full code at issue is quite complicated, but let me see if I can summarize without eliding anything that might be relevant. The idea is basically we have some types which represent our database, and many of those have a field Then we generate further factories which, given some such database value, generate valid children of that database value, automatically setting |
Bug Report
🔎 Search Terms
intersection assign never
🕗 Version & Regression Information
This is the behavior in every version I tried (including nightly), and I reviewed the FAQ for relevant entries. But really this is a loose end left by #36696; prior to that the impossible intersection (
AB
below) was notnever
at all.⏯ Playground Link
link
💻 Code
(modified from the example in #36696)
🙁 Actual behavior
any
is assignable toAB
, despite the fact thatany
is not assignable tonever
andAB
is supposedlynever
(per both #36696 and hovering it)🙂 Expected behavior
any
should not be assignable toAB
The text was updated successfully, but these errors were encountered: