Replies: 1 comment
-
There are a few problems with your approach. Pyright special-cases the FooType = Literal[1, 2] Second, when you assign a dict expression to a TypedDict (as in {
"name": <value type is str>,
"type": <value type is Literal[1] | Literal[2]>
} There is no TypedDict that supports a So here's one solution that eliminates all type errors: FooType = Literal[1, 2]
class Foo:
name: str
type: FooType
# required for type B
description: Optional[str]
def to_dict(self) -> FooDict:
foo_dict: FooDict
if self.type == 1:
foo_dict = {"name": self.name, "type": 1}
elif self.type == 2:
foo_dict = {"name": self.name, "type": 2, "description": self.description}
else:
raise ValueError('Unexpected type')
return foo_dict This approach would also work with enums: class FooType(Enum):
A = 1
B = 2
... # etc
class Foo:
name: str
type: FooType
# required for type B
description: Optional[str]
def to_dict(self) -> FooDict:
foo_dict: FooDict
if self.type == FooType.A:
foo_dict = {"name": self.name, "type": 1}
elif self.type == FooType.B:
foo_dict = {"name": self.name, "type": 2, "description": self.description}
else:
raise ValueError('Unexpected type')
return foo_dict I don't fully understand what you're trying to do here, but it seems odd that the class |
Beta Was this translation helpful? Give feedback.
-
I have a question about type-narrowing and tagged-union typeddicts, specifically with Pyright I suppose narrowing earlier than I would like,
In a project I have a Payload sent to (and from) an API with multiple keys omitted or included depending on the
type
key value.e.g. (in reality there are about 10 different types at this point)
I use a tagged-union of these typeddicts as the return parameter of a function which generates this from an instance of a class.
mypy
will spit out an error on the line definingfoo_dict
saying the Type is ambiguous, which, is true (not sure i agree with erroring there but so-be it, the type revealed below however will be corectly interprited as_FooDictB
.Something like:
My issue is, in the
if self.description is not None
block, after the assert the revealed type will beNever
because pyright has I'm assuming from theself.type.value
beingAny
lazily narrowed the tagged-union to the first option_FooDictA
rather than keeeping the Union intact.I'm opening this discussion to ask if anyone has a suggestion on how to, effectivly keep the union intact in this situation, I could use
cast(FooDict, ...)
to reset the narrowing just after the fact but that sort of feels clunky to me, other option I've got is just to ignore the issue since it's inNever
land the type-checker won't care anyway, but again doesn't feel right to me.Thoughts?
Beta Was this translation helpful? Give feedback.
All reactions