-
Notifications
You must be signed in to change notification settings - Fork 12.5k
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
Unexpected type failure #57775
Comments
I don't think this is true, because if I remove the string case it is suddenly valid. IOW, this code produces no error, even though it would have the same issue with
|
|
Whether or not it is a "proper" discriminated union, both |
It doesn't really make sense to me that there exist any types |
@ahejlsberg Remember when I wrote this comment #57231 (comment) saying such types probably exist in the wild? Yeah, someone pick up that phone because I called it. |
This type doesn't make any sense; there's no way to soundly access type T = { foo: string, data: { } } TypeScript doesn't have negated types and efforts to mimic them will, of course, not succeed. |
Please don't tell me that my stuff does not make sense, you know nothing about my code and you shouldn't pretend to do it. Our actual types are something like this:
and we want calls to succeed for all event types, but no one is actually looking inside the data after we have converted it to an Can we work around this? Yes we can (for example by saying But still, as I wrote above: It doesn't make sense that there are any types T1 and T2 such that there is any value that is assignable to T1 but not to T1 | T2. |
You wrote code thinking it would work a certain way and it doesn't. This is because the type as written doesn't make sense under the rules of the type system. We have no doubt the code makes sense to you, but it doesn't make sense to TypeScript under the rules of the type system as designed. That's what Ryan is saying.
I don't know what you mean by this because there indeed is no such type. In fact that's the root of your problem: What you'd need for this to work properly is a way to express type T = { foo: string & not "bar" & not "baz", data: { x: number } }; AKA negated types. #4196 |
This issue has been marked as "Not a Defect" and has seen no recent activity. It has been automatically closed for house-keeping purposes. |
There is:
@RyanCavanaugh this is the reason I reported it. I know what I'm doing is a little fishy, but there is a value that is assignable to a type |
The problem is the type |
From an ideal perspective, there is no question about whether the value satisfies Is this worth fixing in TS? I don't know. But it absolutely means that TS deviates from an ideal constraint checker. |
To be clear, this isn't an assignability issue. The value is assignable to the type type T1 = { foo: string, data: { x: number } }
type T2 = { foo: 'bar', data: {} } | { foo: 'baz', data: {} }
type T = T1 | T2 ;
function ok(t: T) { }
declare const p: 'bar' | 'baz'
// Validation of the value
const value: T2 = { foo: p, data: {}};
// Assignability of the value
ok(value);
// Does not validate
const value2: T = { foo: p, data: {}}; Where you get hung up is before assignment... This is a validation issue. Think like excess property checks, except there is a stronger case for an error here because the value can absolutely be construed as a malformed It's not necessarily uncommon for a distinction represented in the types to correlate to another distinction not represented in the types (e.g. brand types). Accepting a value where you can't validly rule out a malformed Is it practical? I don't know. I see the utility of the type you're trying to portray here, but there is still a possible logic error being identified, and a very subtle one at that, so while I might be irritated too if I were bit by this the way you were, ultimately I think this is the desirable behavior and I certainly couldn't find my way to labeling it as incorrect. |
Thank you, that was a good explanation.
This is probably for the better, then. It's probably better to reject some valid programs than to accept more invalid ones. |
π Search Terms
Couldn't think of any :(
π Version & Regression Information
β― Playground Link
https://www.typescriptlang.org/play?#code/C4TwDgpgBAKlC8UDeUBmB7dAuKBnYATgJYB2A5gDRQAmAhsLTigB44kCuAtgEYQFQBfQVAA+yNJhwBybrQJSqdBkyFCxKDNigzaALwU16jZKoDcAKHOp2JAMbAi6EmgCMACjDTZ80dtn6ASmRzKFCodABrNw1JKDBFIxUBAPMBS2s7BydwqOAcGCCkVPMgA
π» Code
π Actual behavior
I get an error message
π Expected behavior
No errors
Additional information about the issue
If I change the parameter to
p: 'bar'
, it works. If I change it top: 'baz'
, it works. If I remove the{ foo: string; ... }
option from the union type, it works. But something confuses TS with this specific combination.The text was updated successfully, but these errors were encountered: