question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Proposal: Partial Type Argument Inference

See original GitHub issue

After exploring the concept in #23696, we’ve come to the conclusion that implicitly making type arguments available by name would unnecessarily expose previously unobservable implementation details. As such, I’ll be breaking that proposal down into two parts. One is just the partial inference (which is here), which can stand on its own, as discussed in #20122 and #10571.

To recap, partial type argument inference is the idea that some number of type arguments in a type argument list may be provided, while others are elided and fulfilled via inference using the rest. Specifically, in #10571 a number of different syntax proposals will brought forward:

For the following examples, assume we have a

declare foo<A,B,C>(): [A, B, C];

Variant 1 - elided entries

foo<,,string>(); // returns [{}, {}, string]

This is the most terse option, as simply the lack of inputs implies inference sites. This would almost seem to logically follow from how not providing a list also causes inference to occur at all sites. This does have issues, however: specifying a final parameter as needing inference would require a trailing , in the list (something we currently explicitly disallow), and lists could very easily become confusing, as a , is very easy to skip over.

Variant 2 - Sigil marker

foo<*, *, string>(); // returns [{}, {}, string]

As the second most terse option, this also has appeal; however I think it also fails on a few points. First, * is non-obvious what it means; it implies a “wildcard” of some kind, but in the context of types that could mean an inferred type, a bound, or an existential. Second, as a single-character sigil, we’re unlikely to meaningfully provide completions for it even though it is contextually relevant. Finally, we’re considering other work to do with existentials and generated type parameters in the future which we’d like to be able to use the * as an indicator for.

Variant 3 - Keyword marker

a. auto

foo<auto, auto, string>(); // returns [{}, {}, string]

b. infer

foo<infer, infer, string>(); // returns [{}, {}, string]

Neither of these are as terse as the others, but both are still likely substantially shorter than providing the entire list of types by hand in situations where partial inference is desired. Of the two keywords, auto may be shorter, but currently carries no meaning within the language. infer on the other hand is already used for marking inference positions within conditional types. The infer method was explored in #22368, however was taken much father - almost fully replicating the arbitrary placement and naming the operator affords within conditional types.

In the end, I’m advocating for variant 3b - the infer placeholder, with none of the extra features afforded in #22368 (we can always add them later if there is demand).

Issue Analytics

  • State:open
  • Created 5 years ago
  • Reactions:651
  • Comments:86 (17 by maintainers)

github_iconTop GitHub Comments

55reactions
jsiwhiteheadcommented, Aug 9, 2018

Will this include the option for simply omitting trailing type arguments, and having them automatically set as inferred?

Ie for these to be equivalent:

foo<string, infer, infer>();

foo<string>();
43reactions
jcalzcommented, Jan 28, 2022

This is one of those issues that keeps. coming. up. in Stack Overflow questions, both directly (“how can I specify this type parameter and have the compiler infer the rest”) and indirectly (“yes this solution works but isn’t there some way to get rid of that weird seemingly no-op curried function call you’re doing at the beginning?”)

In the absence of just making <T, U>(u: U) => xxx work magically with when called like f<T>(u), it would still be so much nicer to be able to write <T, U=infer>(u: U) => xxx instead of the current <T,>() => <U,>(u: U) => xxx with f<T>()(u), or <T, U>(dummyT: T, u: U) => xxx with f(null! as T, u).

Read more comments on GitHub >

github_iconTop Results From Across the Web

Partial type argument inference in typescript and workarounds ...
As implicit type inference is always an optional feature, type arguments can be provided explicitly in the function call. Usecase that needs ...
Read more >
Typescript partial type inference - Stack Overflow
Type inference works based on an all or nothing principle. In the first case: fn({ a: 1 }). has no generic type parameters...
Read more >
Partial type annotations - Discussion - Swift Forums
It's always seemed weird to me that we let you write let x: Generic = foo() to infer the generic arguments, but not...
Read more >
Spine-local Type Inference - ACM Digital Library
synthesize a type. The techniques proposed in the literature for ... its partial elaboration p from type-argument inference fills in each.
Read more >
Is there any progress on partial type argument inference?
15 votes, 11 comments. A very old pain point of TypeScript is the fact that type arguments cannot be partially inferred.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found