Skip to content

Structural Pattern Matching for Types #1966

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
zach-waggoner opened this issue Apr 10, 2025 · 1 comment
Open

Structural Pattern Matching for Types #1966

zach-waggoner opened this issue Apr 10, 2025 · 1 comment
Labels
topic: feature Discussions about new features for Python's type annotations

Comments

@zach-waggoner
Copy link

zach-waggoner commented Apr 10, 2025

I'm sure that there are other use cases for this, but the main one that comes to mind is inferring the type of function parameters. It is common that you want to override a superclass method, for example, which may accept many parameters that you don't need in the override:

class MyClass(BaseClass):
    def my_method(self, *args, **kwargs):
        ...
        return super().my_method(*args, **kwargs)

Unfortunately, most libraries, even if they provide type stubs, do not provide a TypedDict subclass that you can simply import in order to use Unpack[MyMethodKwargs], so the only way to not lose typing information is to redeclare all of the parameters.

If we could infer a ParamSpec type from the method type, and if we could infer the method type from the method object, then we could do something like:

class MyClass(BaseClass):
    def my_method(
        self,
        *args: Params[type[BaseClass.my_method]].args,
        **kwargs: Params[type[BaseClass.my_method]].kwargs,
    ):
        ...
        return super().my_method(*args, **kwargs)

I think that Python badly needs this, as **kwargs is so ubiquitous and one of the most notable places where type information is lost in my experience.

The way that TypeScript implements this is by leveraging pattern matching within conditional types:

type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;

This would be a very cool feature as it could be used for many other patterns, enabling things like Params[T], ReturnType[T], KeyOf[T], ValueOf[T], etc.

Unfortunately, since expressions were not implemented for structural pattern matching, we can't directly mirror the syntax, but it could maybe look something like:

type Params[C: Callable[..., Any]] = match C: P if case Callable[P, Any] else Never

or:

type Params[C: Callable[..., Any]] match C:
    case Callable[P, Any]: P
    case _: Never
@zach-waggoner zach-waggoner added the topic: feature Discussions about new features for Python's type annotations label Apr 10, 2025
@zach-waggoner zach-waggoner changed the title Pattern Matching for Types Structural Pattern Matching for Types Apr 10, 2025
@jorenham
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
topic: feature Discussions about new features for Python's type annotations
Projects
None yet
Development

No branches or pull requests

2 participants