Skip to content

Commit d23f5f0

Browse files
JiwaniZakirClaude Agent
andauthored
Fix false positive "Expected TypedDict key to be string literal" for Union[TypedDict, dict[K, V]] (#21511)
When a variable is typed as `Union[TypedDict, dict[int, float]]`, mypy incorrectly raised `Expected TypedDict key to be string literal` when assigning a dict literal with non-string keys like `{1: 5.2}`. The plain `dict[int, float]` alternative makes the assignment valid, so this was a false positive. The root cause was that `match_typeddict_call_with_dict`, which is used as a probe to check whether a dict literal could match a TypedDict, was emitting errors from `validate_typeddict_kwargs` during the matching phase rather than silently returning `False`. Wrapping the call in `filter_errors()` suppresses those spurious diagnostics. Fixes #21510 Co-authored-by: Claude Agent <agent@example.com>
1 parent 5e0c274 commit d23f5f0

2 files changed

Lines changed: 14 additions & 1 deletion

File tree

mypy/checkexpr.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -932,7 +932,8 @@ def match_typeddict_call_with_dict(
932932
kwargs: list[tuple[Expression | None, Expression]],
933933
context: Context,
934934
) -> bool:
935-
result = self.validate_typeddict_kwargs(kwargs=kwargs, callee=callee)
935+
with self.msg.filter_errors():
936+
result = self.validate_typeddict_kwargs(kwargs=kwargs, callee=callee)
936937
if result is not None:
937938
validated_kwargs, _ = result
938939
return callee.required_keys <= set(validated_kwargs.keys()) <= set(callee.items.keys())

test-data/unit/check-typeddict.test

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -941,6 +941,18 @@ c: Union[A, B] = {'@type': 'a-type', 'value': 'Test'} # E: Type of TypedDict is
941941
[builtins fixtures/dict.pyi]
942942
[typing fixtures/typing-typeddict.pyi]
943943

944+
[case testTypedDictUnionWithNonTypedDictLiteralKey]
945+
from typing import Union, TypedDict
946+
947+
class Foo(TypedDict):
948+
some: str
949+
name: str
950+
951+
baz: Union[Foo, dict[int, float]] = {1: 5.2}
952+
baz2: Union[Foo, dict[int, float]] = {'some': 'x', 'name': 'y'}
953+
[builtins fixtures/dict.pyi]
954+
[typing fixtures/typing-typeddict.pyi]
955+
944956
-- Use dict literals
945957

946958
[case testTypedDictDictLiterals]

0 commit comments

Comments
 (0)