Feat: add new --all-fields-required flag (addresses #28: Field with default value becomes optional)
#57
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.
Summary
Fixes: #28
Adds an
--all-fields-requiredoption (defaults toFalse) that ensures no generated TypeScript interface fields are marked as optional (fieldName?: ...), even if they have default values or default factories in the Pydantic models.Motivation
Fields with defaults are viewed as optional by Pydantic, and thus currently become optional in the generated TypeScript interfaces.
This makes sense for API request schemas: clients don't need to provide values for these fields, since Pydantic can populate them with their defaults. However, for response schemas, the TS client should be able to know that these fields will be present, since Pydantic will populate them before sending the response data.
So, this new option (
--all-fields-required) allows devs to represent response schemas without unnecessary optional markers (?) being added to fields that will always be present.Approach
The implementation is nice and simple: at the end of each
_clean_json_schemacall, if--all-fields-requiredis set, we ensure every property name inschema["properties"]is included inschema["required"].Comparison to existing PR #31
An existing PR (#31, filed by @bibermann in 2022) implements a similar flag
--readonly-interfacesand is also marked to resolve #28.It takes a slightly different approach, only operating on Pydantic V1 models (Pydantic V2 didn't exist back then), and marking a field as required if
allow_noneis true.Under that approach, fields could still be marked as optional in the generated TS interfaces. E.g. under
--readonly-interfaces, this:would be generated into this:
Whereas under
--all-fields-requiredit would be generated into this:As we can see, another difference in the outputs is the existence of
nulltypes, but that's because of the pydantic2ts v2.0.0 release in Nov 2024.Note on required fields in Pydantic V1 vs V2
Under Pydantic V1, nullable fields were implicitly given default values of
None, which the Pydantic docs mention here:Note
In Pydantic V1, fields annotated with Optional or Any would be given an implicit default of None even if no default was explicitly specified. This behavior has changed in Pydantic V2, and there are no longer any type annotations that will result in a field having an implicit default value.
But since
--all-fields-requiredis just meant to mark every field as required whether or not it has a default or is nullable, our approach should be sound for either V1 or V2.