-
-
Notifications
You must be signed in to change notification settings - Fork 544
anyOf clauses are combined via intersection (&), should be union (|) #462
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
I did a quick research, it seems that But when I run a test with the code provided by @dbjorge the result is just an union, which I understand is not correct: export type Example =
| {
anyof_prop_common: "a";
anyof_prop_a?: string;
[k: string]: unknown;
}
| {
anyof_prop_common: "b";
anyof_prop_b?: string;
[k: string]: unknown;
}; |
Or maybe it is correct? TypeScript is still a myth to me. I thought typescript unions were exclusive, but doesn't seem to be? type HasEmail = {
email: string
}
type HasName = {
name: string
}
type AnyOf = HasEmail | HasName
// accepts both properties?!
const test: AnyOf = {
name: 'test',
email: 'yo'
} So I guess a union is the correct type here? TypeScript still confuses me ... 😕 |
I think that a union ( |
I agree that What I don't understand though is this claim in the linked SO answer: type AnyOfSample = HasName | HasEmail | (HasName & HasEmail) // same thing The above code is not the same as type AnyOfSample = HasName | HasEmail and would in fact be preferable. See this playground |
Or am I missing something? |
No, I did have the terms right I think, nevermind this |
evergreen ☝️🤣 |
Your playground example is pretty compelling; it does feel like there's cases where just union on its own is incomplete. I'm not sure it's as simple as |
Yes, I think |
So I was convinced by @andrewbranch and @smockle that we should do a simple union of all possible items. I'll post the whole discussion here once both agree that it's ok (@smockle already did, just wanting for @andrewbranch +1). Here is an example to showcase that it works by Andrew: playground The limitation is that using an object as an intersection of the union would currently fail, see the last @andrewbranch suggested that TypeScript's current behavior of narrowing the result with |
Here is the chat log for reference, lots of insights! I copied from Slack and tried to clean it up, I hope I didn't mess up anything
|
Is this resolved in #491? Or is something additional needed? |
I think this is resolved as good as it can be |
I'm sorry to reply to the closed issue. TypeScript union ( So |
Summary
The transformation rules for an object schema with an
anyOf
clause look like this:https://github.com/drwpow/openapi-typescript/blob/8a999ebaea31140b24632f6439dc3d4a41caa319/src/transform/schema.ts#L39-L41
This should be using a union, not an intersection.
Impact
This comes up in the GitHub OpenAPI specification (see https://github.com/octokit/rest.js/issues/2000 for one example in the check/update operation).
Explanation/repro
This StackOverflow answer is a pretty thorough writeup of why a union would be more appropriate.
As an example where the current behavior is problematic, consider this case:
Related cases
Separately from this bug, the same SO post I linked above has a good discussion of how to handle
oneOf
, which is much harder to convert in a way that is accurate. Personally, I think it is more valuable for this library to produce typings that are over-accepting than under-accepting, so based on the tradeoffs that SO post talks about, I would recommend keeping the current oneOf behavior (ie, oneOf and anyOf will produce identical typings) and consider it acceptable that this will cause the library to be over-accepting of cases where aoneOf
schema should reject input thatanyOf
would accept.This bug was discovered at the same time/for the same motivating case as #461, but is a separate root cause.
The text was updated successfully, but these errors were encountered: