Skip to content

Feat: add new --all-fields-required flag #2

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

Merged
merged 9 commits into from
Apr 11, 2025

Conversation

alythobani
Copy link
Owner

Fixes #1

Copied over from phillipdupuis#57:

Summary

Adds an --all-fields-required option (defaults to False) 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_schema call, if --all-fields-required is set, we ensure every property name in schema["properties"] is included in schema["required"].

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-required is 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.

…uired

Previously, some Pydantic models that were only indirectly referenced
(e.g. buried inside an Annotated[Union[...]] field) weren't processed
before final schema generation. As a result, their default-valued fields
would be optional in the TypeScript output, even when
all_fields_required was set.

We now recursively walk and collect all reachable models before calling
`_clean_json_schema`, ensuring all schemas are properly processed.
…h v1 and v2 models)

- revert last 4 commits (serialization aliases and walking all models)
- just add any property names from the schema directly into `required`
  instead of working with the model fields directly and needing to
  account for aliases
- walking models no longer needed for all-fields-required to apply to
  all models used; even if `model` is None we still handle the schema
@alythobani alythobani changed the title Feat: add new --all-fields-required flag (addresses #28: Field with default value becomes optional) Feat: add new --all-fields-required flag Apr 11, 2025
@alythobani alythobani changed the title Feat: add new --all-fields-required flag Feat: add new --all-fields-required flag Apr 11, 2025
@alythobani alythobani merged commit bbf45c1 into main Apr 11, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Field with default value becomes optional on the TypeScript interface
1 participant