support dictionary literal `TypedDict` constructors

This commit is contained in:
Ibraheem Ahmed 2025-10-07 16:44:48 -04:00
parent b753851379
commit 2949f76b47
2 changed files with 37 additions and 10 deletions

View File

@ -315,6 +315,8 @@ Person(name="Alice", age=30, extra=True) # type: ignore
The positional dictionary constructor pattern (used by libraries like strawberry) should work
correctly:
`class.py`:
```py
from typing import TypedDict
@ -335,6 +337,26 @@ user3 = User({"name": None, "age": 25})
user4 = User({"name": "Charlie", "age": 30, "extra": True})
```
`functional.py`:
```py
from typing import TypedDict
User = TypedDict("User", {"name": str, "age": int})
# Valid usage - all required fields provided
user1 = User({"name": "Alice", "age": 30})
# error: [missing-typed-dict-key] "Missing required key 'age' in TypedDict `User` constructor"
user2 = User({"name": "Bob"})
# error: [invalid-argument-type] "Invalid argument to key "name" with declared type `str` on TypedDict `User`: value of type `None`"
user3 = User({"name": None, "age": 25})
# error: [invalid-key] "Invalid key access on TypedDict `User`: Unknown key "extra""
user4 = User({"name": "Charlie", "age": 30, "extra": True})
```
## Optional fields with `total=False`
By default, all fields in a `TypedDict` are required (`total=True`). You can make all fields

View File

@ -4865,16 +4865,21 @@ impl<'db> Type<'db> {
Type::EnumLiteral(enum_literal) => enum_literal.enum_class_instance(db).bindings(db),
Type::KnownInstance(KnownInstanceType::TypedDictType(typed_dict)) => Binding::single(
self,
Signature::new(
// TODO: List more specific parameter types here for better code completion.
Parameters::new([Parameter::keyword_variadic(Name::new_static("kwargs"))
.with_annotated_type(Type::any())]),
Some(Type::TypedDict(TypedDictType::Synthesized(typed_dict))),
),
)
.into(),
Type::KnownInstance(KnownInstanceType::TypedDictType(typed_dict)) => {
CallableBinding::from_overloads(
self,
[Signature::new(
// TODO: List more specific parameter types here for better code completion.
Parameters::new([
Parameter::variadic(Name::new_static("args")),
Parameter::keyword_variadic(Name::new_static("kwargs"))
.with_annotated_type(Type::any()),
]),
Some(Type::TypedDict(TypedDictType::Synthesized(typed_dict))),
)],
)
.into()
}
Type::KnownInstance(known_instance) => {
known_instance.instance_fallback(db).bindings(db)