microsoft / TypeScript

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

Allow instantion expression with empty arguments #57510

Open rotu opened 9 months ago

rotu commented 9 months ago

πŸ” Search Terms

instantiation expression, empty, type arguments

βœ… Viability Checklist

⭐ Suggestion

I would like to be able to instantiate a generic function type with an empty type arguments list.

It would be nice to allow this for generic types, but it's not as necessary, since a generic type is always instantiated in a type context, even if no type arguments list is given. A generic function type needs to be specifically instantiated.

πŸ“ƒ Motivating Example

Here is a generic function where a type parameter has a default. I can get use an instantiation expression to specialize it to a non-generic function.

declare function find1<T, S extends T=T>(Ar:T[], predicate:(t:T)=>t is S): S | undefined;
type Find1Object = typeof find1<object>;

Here is a generic function with only one type parameter. I cannot use an instantiation expression with the default for S:

declare function find2<S extends object = object>(Ar:object[], predicate:(t:object)=>t is S) : S | undefined;
type Find2 = typeof find2<>; // <- this is a syntax error "Type argument list cannot be empty"

πŸ’» Use Cases

  1. What do you want to use this for?
  2. What shortcomings exist with current approaches?
  3. What workarounds are you using in the meantime?
    • Declare an unused "dummy" type parameter so there's always a non-defaulted type argument.

Originally mentioned here: https://github.com/microsoft/TypeScript/issues/57463#issuecomment-1957739330

RyanCavanaugh commented 9 months ago

@ahejlsberg any thoughts? Seems straightforward enough?

jcalz commented 1 week ago

Can we get this for calling the function directly also? That is: just support empty type argument lists for generic functions, if all of the type parameters have defaults. It would be weird for (f<>)() to work but for f<>() not to work.