0

In TypeScript I can write something like:

function foo<T>(a: T): T{
}

function foo<T extends A>(a: T): T{
}

And TypeScript will know that if I call let myVar = foo(1), myVar will be a number

How can I achieve the same result in Python?

Basically, I'm using prometheus-client, and I want to create a utility function that allows you to register a Metric of any type. The function should then return the metric, of the same type.

So if I call

def register_metric(metric: Metric) -> Metric


my_summary = register_metric(Summary("some_summary", "summary description"))

my_counter = register_metric(Counter("some_counter", "counter description"))

then my_summary will be a Summary and my IDE will know that I have the .observe method while my_counter will be a Counter with the .inc method

EDIT: I noticed the typing Generics which allows me to create a T variable. I can't seem to figure out how to limit it to only sub-classes of Metric, similar to how in TypeScript I can do <T extends A>

Stichiboi
  • 79
  • 1
  • 5

1 Answers1

0

Suppose you have a class hierarchy like this

class Metric:
    pass


class Summary(Metric):
    pass


class Counter(Metric):
    pass

You can define a TypeVar with bound=Metric, indicating that the TypeVar must be a type that "an actual type substituted (explicitly or implicitly) for the type variable must be a subclass of the boundary type" (TypeVar).

from typing import TypeVar

MetricT = TypeVar("MetricT", bound=Metric)

Then you can use MetricT to define register_metric:

def register_metric(metric: MetricT) -> MetricT:
    return metric


summary = register_metric(Summary())
counter = register_metric(Counter())

Result:

reveal_type(summary)  # Type of "summary" is "Summary"
reveal_type(counter)  # Type of "summary" is "Counter"
PIG208
  • 2,060
  • 2
  • 10
  • 25