basedmypy icon indicating copy to clipboard operation
basedmypy copied to clipboard

A `MappedType` type

Open KotlinIsland opened this issue 3 years ago • 3 comments

Like TypedDict but based.

  • Support any Mapping including a covariant version of dict
  • Usable as a type parameter on functions unrelated to maps
  • Support any key type
  • Control over additional keys
    • exclude additional keys
    • specify type bounds
class Foo(MappedType):
    a: int

f: defaultdict[Foo.Key, Foo.Value] = defaultdict(None, a=1)
reveal_type(f)  # defaultdict & Foo

def foo(a: Foo.Key) -> Foo.Value: ...

foo('a')  # int
class Foo(MappedType):
    Key[1]: int

Or

@dataclass
class Thing:
    key: type
    value: type

KV = MappedTypeVar("KV", Thing("hi", str), Thing("bye", int))
# Alternative shorthand
# KV = MappedTypeVar("KV", mapping={"hi": str, "bye": int})

def foo(k: KV.key) -> KV.value: ...
reveal_type(foo("hi"))  # str
reveal_type(foo("bye"))  # int


def bar(k: KV.key, v: KV.value): ...
bar("hi", 1)  # error, expected str, found int


class A:
    def __getattr__(self, item: KV.key) -> KV.value: ...

a = A()
reveal_type(a.hi)  # str


ListY = TypeVar("ListY", [1, 2, 3], [2, 3, 4])
def bar_y(k: KVX[0], v: KVX[1]) -> KVX[2]: ... 
bar_y(2, 3)  # 4

Prior art

TS be like

type Thing = {
    hi: string
    bye: nuber
}

declare function foo<K extends keyof Thing>(t: K) -> Thing[K]

This has the limitation of only being key/value where the key is string | number | Symbol.

KotlinIsland avatar Feb 17 '22 04:02 KotlinIsland