swagger-to-ts 2.0: better type generation #178
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
In thinking about support for OpenAPI3, it became clear that this project’s code quality needed to improve. The first iteration was made to solve a work problem quickly and cheaply, resulting in sort of a spaghetti mess that worked for us, but broke for more complicated schemas. With more and more people depending on this and needing OpenAPI3, some changes are needed.
A major inspiration for this change is a TS genration library I rely on almost daily: GraphQL Code Generator. If you’ve used that library, this change will feel familiar to you.
Changing the generated types would break integrations for most, so this would mean a
2.0
release of swagger-to-ts. But this change is a better direction for the project overall, because it more closely matches your schema, the source of truth. I wrote a newREADME
section explaining some of the reasoning (below), but here’s a TL;DR:$ref
s, without changing or inventing anyallOf
andadditionalProperties
To try this version yourself:
New README section:
Upgrading from v1 to v2
Some options were removed in v2 that will break existing setups, but don’t worry—it actually gives
you more control, and it generates more resilient types.
Explanation
In order to explain the change, let’s go through an example with the following Swagger definition
(partial):
This is how v1 would have generated those types:
Uh oh. It tried to be intelligent, and keep interfaces shallow by transforming
user.role
intoUserRole.
However, we also have anotheruser_role
entry that has a conflictingUserRole
interface. This is not what we want.
v1 of this project made certain assumptions about your schema that don’t always hold true. This is how v2 generates types from that same schema:
This matches your schema more accurately, and doesn’t try to be clever by keeping things shallow. It’s also more predictable, with the generated types matching your schema naming. In your code here’s what would change:
While this is a change, it’s more predictable. Now you don’t have to guess whether or not
user_role
was renamed as; you simply chain your type from the Swagger definition you‘re used to.Better refs
swagger-to-ts also preserves your
$ref
s from Swagger. Notice how the old version invented a ref forUser.role
that at worst causes conflicts with other parts of your schema; at best is unpredictable. Transforming your schema as-is relies on your schema to handle collisions (which will probably get it right), rather than swagger-to-ts (which probably won’t).Wrappers
The
--wrapper
CLI flag was removed because it was awkward having to manage part of your TypeScript definition in a CLI flag. In v2, simply compose the wrapper yourself however you’d like:CamelCasing
Similarly, the
--camelcase
was removed because it transformed your schema in unpredictable ways. It didn’t always transform words as expected. In v2, all generated types must conform to your schema’s exact naming.