-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
Declare a function as a type; or, defer resolving generic types when declaring a variable as a type #29613
Comments
Previously suggested in similar forms I think this proposal tries to sort of do all of them at once and would be best tackled individually. I can't say for sure that it's fatal, but the syntactic confusion problem here is overwhelming for the case where the function type is generic (ignoring the position of the annotation for the moment): function myStupidFunction(arg, transform) {
return transform(arg);
}: MyStupidType<A, B>;
// ... ? ...
function myStupidFunction(arg, transform) {
return transform(arg);
}: MyStupidType<string, number>; It's extremely unclear here whether the type arguments are introducing new types with those names, or referencing existing types by those names. Similarly here: const myStupidFunction: MyStupidType<infer A, infer B> = (arg, transform) => transform(arg); My reading is that this is a non-generic function with two (implicit) Like other names, type arguments need to be introduced in an unambiguous syntax that makes it reasonably clear to the reader what's going on. Right now, in a type annotation position, |
@RyanCavanaugh Thanks for taking a look at this. Having looked at the tickets you referenced, I do agree that #16918 and #19106 address the first part of the problem (whole-typed functions) and #17574 is a more thoroughgoing solution to the second part (deferred generics, which I believe is very similar to what @maseedu is calling "arbitrary parametric polymorphism"). Going over it now I do think I was mixing up some concerns. I'll split them up below to see if any of them are worth investigating. Setting aside polymorphism completely, whole-typing functions is intuitive in the case of arrow functions:
It can also be done with function declarations:
But that's a pretty ugly syntax (and also not exactly equivalent because of hoisting). My favourite syntax of the ones I suggested is
I can propose that over on #16918 and dispense with it here. Then there's arbitrary polymorphism. #17574 doesn't seem to propose a syntax, but it does seem like some kind of syntax would be necessary for some of the cases the issue is describing (e.g.
—in the pie-in-the-sky scenario here, what would one use in place of However—and this is the core motivation for my suggestion—a thoroughgoing solution for arbitrary polymorphism looks a long way off (because of problems discovered investigating #9366, #9949, also see #24626; I believe this concern would affect any complete implementation of #16918 but please correct me if I am wrong), while a special syntax for whole-typing functions is comparatively easy. It just happens that in the particular case where we're typing a function declaration, this:
is a restatement of this already supported syntax:
With the added benefit of type-checking with a reusable interface. My point is that if we can agree on
Then we have an opportunity to get the benefits of arbitrary polymorphism on whole-typed functions without having to tackle the hard problems of solving the general case—because what I'm proposing is equivalent to what the engine is already doing. |
This issue has been marked as a 'Duplicate' and has seen no recent activity. It has been automatically closed for house-keeping purposes. |
Search Terms
Suggestion
This comprises two suggestions in one as I want to leave it up you to decide which is better value-for-effort. The suggestions are also compatible with each other.
1: typing a function
When declaring a function, I want to be able to declare the type of the function as a whole, not just the type of the parameters or the return value. I want this to be compatible with generic types just like the existing function declaration syntax is.
Example:
The above is idiomatic, but clunky, so an alternative suggested syntax is:
Since the function may not even have to reference the generic types explicitly (as in the example), it may even be possible to drop them, like so:
Or like so:
Or like so:
2: typing a const generically
The usual workaround for the problem I'm facing is to use arrow functions instead:
As you can see, this doesn't work with generics, because I have to make the function non-generic in order to declare it in this way.
The proposed change is to allow the
const
to remain generic using theinfer
keyword:...or, as suggested in 1), just dropping them if they do not need to be directly referenced:
Use Cases
I ran into the problem described in #9366 while playing with types describing reducers (in an attempt to building up to understanding transducers):
This of course doesn't work because
AbstractReduce
is being referenced with no type parameters. But my implementation here is still too abstract for me to want to supply them.However, this works:
This would be fine except that it means I can't use my interface, because there's no way to tell TypeScript that a function implements a generic interface (as opposed to its parameters or return type considered individually).
The overall problem of deferring resolution of generics until a function is called turns out to be extremely difficult under the constraints of TypeScript; but what I'm proposing (hopefully) is not and it suffices for my use case.
Examples
The above sections show examples. When a developer writes a function that needs to implement a type, they can use the above syntax to allow TypeScript to extend the current behaviour around function declarations to function declarations that implement types.
Checklist
My suggestion meets these guidelines:
The text was updated successfully, but these errors were encountered: