Matija Sirk
Matija Sirk

Reputation: 960

Why are TypedDict types without field and with NotRequired field incompatible?

I am trying to create a few functions which will return values of different TypedDict types. Most of fields in them will be same so I want to generate base dictionary with same function in all cases. However I am getting stumped by typing this correctly.

My idea was to create base type Parent and inherit from it, adding only NotRequired fields.

from typing_extensions import NotRequired, TypedDict

class Parent(TypedDict):
    parent_field: str


class Child(Parent):
    child_field: NotRequired[bool | None]


def create_parent() -> Parent:
    return {"parent_field": "example"}


child: Child = create_parent()
# Error:
# Expression of type "Parent" cannot be assigned to declared type "Child"
#  "child_field" is missing from "Type[Parent]"

However this fails since field child_field is missing, even though its type is NotRequired. Why it fails and how to evade this problem?

EDIT: I am using pylance (so pyright) for typechecking.

mypy (playground) gives similar error message:

Incompatible types in assignment (expression has type "Parent", variable has type "Child") [assignment]

Upvotes: 3

Views: 1588

Answers (1)

STerliakov
STerliakov

Reputation: 7963

This question is explained in PEP589 explicitly. Let me quote:

A TypedDict type A with no key x is not consistent with a TypedDict type with a non-required key x, since at runtime the key x could be present and have an incompatible type (which may not be visible through A due to structural subtyping). Example:

class A(TypedDict, total=False):
    x: int
    y: int

class B(TypedDict, total=False):
    x: int

class C(TypedDict, total=False):
    x: int
    y: str

 def f(a: A) -> None:
     a['y'] = 1

 def g(b: B) -> None:
     f(b)  # Type check error: 'B' incompatible with 'A'

 c: C = {'x': 0, 'y': 'foo'}
 g(c)
 c['y'] + 'bar'  # Runtime error: int + str

So, your Parent class is not assignable to variable of type Child, and pylance points it out.

Upvotes: 3

Related Questions