Skip to content

Enhanced Literal Detection: Allow string type narrowing to literals #16813

Closed
@CarliJoy

Description

@CarliJoy

Feature

It would be great if mypy could detect and type narrow strings to Literals if this is statically detectable.
I.e. if accessing TypedDict or Enum values

Pitch

from typing import TypedDict

class Part(TypedDict, total=False):
    a: int
    b: int

class Full(Part, total=False):
    c: int

def make_part(full: Full) -> Part:
    part: Part = {}
    for k, v in full.items():
        if k in Part.__annotations__:
            part[k]=v  #  error: TypedDict key must be a string literal; expected one of ("a", "b")  [literal-required]
    return part 

MyPy Play

Currently there is no way to type this kind of expression without a # type: ignore.

It would be nice if mypy could detect that if k in Part.__annotations__ will narrow k to the Literal of all key of Part.
Also if k == "a" isn't working at the moment, but at least for this I am able to write a TypeGuard.

Also if Literals are explicitly defined, we loose this once we are with a loop

Even if the literal is defined explictly, it gets lost in a for loop

def make_part_two(full: Full) -> Part:
    part: Part = {}
    keys: Final = ("a", "b")
    reveal_type(keys)  # tuple[Literal['a']?, Literal['b']?]
    ok = full[keys[0]]
    for key in keys:
        reveal_type(key) # str
        part[key] = full[key]  # literal-required

If explicitly given as keys: tuple[Literal["a", "b"], ...] it works also in the for loop but I don't want to duplicate these values...

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions