microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
https://www.typescriptlang.org
Apache License 2.0
100.76k stars 12.46k forks source link

Support generics on first class functions #40149

Open nickserv opened 4 years ago

nickserv commented 4 years ago

Search Terms

first class function generics

Suggestion

I think first class functions are one of the most useful and important advantages that JavaScript has over other modern programming languages. While TypeScript's inference generally works pretty well on first class function arguments, it seems like changing generic arguments on a first class function (without wrapper functions) is not possible the way the generic argument syntax is parsed.

Use Cases

Any case where custom arguments don't need to be passed to a first class function, but generic type arguments do need to be passed. Currently, you have to either pass a first class function without generics or wrap a new function literal to use generics, otherwise you get Argument of type 'T' is not assignable to parameter of type 'F'.(2345), Expected X arguments, but got 0., and An argument for 'T' was not provided..

Examples

Desired syntax with type error: https://www.typescriptlang.org/play?#code/GYVwdgxgLglg9mABBAhgGzQdRlAFgHgBUAaRAJQD4AKFAJwHMAuRExUSZmh5wgSkQC8FcvwDeAWABQiRLQCmUELSTsIXerykBfKbsmrYCWQqVgAggGci1Ok0TgA1mDgB3MLx6IJ044uWJbAIsWbT1UDGw8KgAiOQAPFABbAAc0OWjSeT9zKwsoWhgwegpeIA

Workaround without type errors: https://www.typescriptlang.org/play?#code/GYVwdgxgLglg9mABBAhgGzQdRlAFgHgBUAaRAJQD4AKFAJwHMAuRExUSZmh5wgSkQC8FcvwDeAWABQiRLQCmUELSTsIXerykBfKbsmrYCWQqVgAggGci1Ok0TgA1mDgB3MLx6IJ044uWJbAIsWbT1UDGw8KgAiOQAPFABbAAc0OWjSdX4hX1NLfAsoWhgwehsGXl4gA

Checklist

My suggestion meets these guidelines:

RyanCavanaugh commented 4 years ago

I'm pretty sure we have a suggestion for this already but I can't find it.

Some more compelling examples would be interesting. The example provided could be trivially solved by just writing

callWith("example", returnAs)

which just seems better. What are the concrete use cases where you gain expressiveness?

nickserv commented 4 years ago

I intentionally gave a simplified example since the one I actually wanted involves tons of unrelated types. Basically I wanted to pass a utility function to .map(), but I had to pass it a generic argument to make the type valid, which I can't do without replacing the first class function with a function literal. I could see this being a bigger issue with pointfree programming where function literals are discouraged and the same function may need to be reused with many different types.

jkoudys commented 3 years ago

Any love for the turbofish? returnAs::<string>

xiBread commented 3 years ago

Any love for the turbofish? returnAs::<string>

That could cause problems with the bind operator/extensions proposal.

jcalz commented 2 years ago

Fixed in #47607 I think