Skip to content

Literal field becomes optional in typescript #36

Open

Description

@jcampbell

If I define a property using a Literal with a default value, it shows as optional in typescript. This is similar to #28 but, I think it should be treated differently because the value must be set, even by a client (the property is used as a discriminator in a union).

from typing import Literal
from pydantic import BaseModel


class MyModel(BaseModel):
  my_bool_property: Literal[False] = False

renders into

/* tslint:disable */
/* eslint-disable */
/**
/* This file was automatically generated from pydantic models by running pydantic2ts.
/* Do not modify it by hand - just update the pydantic models and then re-run the script
*/

export interface MyModel {
  my_bool_property?: false;
}

Activity

  1. alythobani commented on Mar 20, 2025

    @alythobani

    I could be misunderstanding your use case here, but I don't actually think this should be treated differently from #28.

    If MyModel is being sent from TypeScript to Python (e.g. as a request), the presence of the default on the Pydantic model means that even if TS doesn't include my_bool_property, it will still be populated as False on the Python side when processing the request data (converting the JSON into a MyModel instance). So in that case, it should be safe to mark my_bool_property as optional on the TS side.

    And if it's being used as a discriminator on the TS side and should be required, that sounds like something pydantic2ts wouldn't have direct knowledge of (but a flag to avoid defaulted-fields becoming optional would solve the issue).

    But yeah maybe I'm missing something in what you were looking for here.

  2. sebbekarlsson commented on Jun 7, 2025

    @sebbekarlsson

    I'm having this issue too

  3. lubosmato commented on Oct 3, 2025

    @lubosmato

    I might have similar "issue" / use-case. I would like to use generated types for calling JSON-RPC 2.0 API in TS environment. Now I use Literal types to "pass" method name into TS as a string literal type.

    from typing import Any, Literal, Optional
    from pydantic import BaseModel
    
    
    JSONRPC_VERSION = "2.0"
    
    
    class JsonRpcPayload(BaseModel):
        method: str | Any
        params: None | Any
        jsonrpc: Literal["2.0"] = JSONRPC_VERSION
        id: Optional[str] = None
    
    
    class SomeRpcMethodPayload(JsonRpcPayload):
        method: Literal["some.rpc.method"] = "some.rpc.method"
        params: None = None
    
    
    payload = SomeRpcMethodPayload()
    print(
        payload.model_dump_json()
    )  # {"method":"some.rpc.method","params":null,"jsonrpc":"2.0","id":null}
    export interface JsonRpcPayload {
      method: unknown;
      params: unknown;
      jsonrpc?: "2.0"; // <-- 
      id?: string | null;
    }
    
    export interface SomeRpcMethodPayload {
      method?: "some.rpc.method"; // <-- 
      params?: null;
      jsonrpc?: "2.0"; // <-- 
      id?: string | null;
    }

    Usage:

    const payload: SomeRpcMethodPayload = {}
    // ^ this approach would work if the property method were not optional
    // and caller would be required to set property method, e.g.:
    // const payload: SomeRpcMethodPayload = {method: "some.rpc.method"}
    
    const result = await fetch("...", {
      method: "POST",
      body: JSON.stringify(payload) // -> "{}" 
    }) // body is empty json

    At the moment this is a bit limiting when Literal python type hint is represented by optional property in Typescript - allowing passing no method property. I understand that this is a feature (not a bug).

    Indeed a flag that would avoid defaulted-fields becoming optional would make possible this use-case.

  4. lubosmato commented on Oct 3, 2025

    @lubosmato

    On second thought, I realize my approach might be somewhat hacky. The underlying pipeline is:
    Pydantic objects → JSON Schema → json2ts → TypeScript types

    Implementing a flag to make defaulted fields required would essentially break Pydantic's serialization conventions. JSON Schema semantics dictate that fields with default values should be marked as optional, which makes perfect sense from a schema validation perspective.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions