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.

Allow skipping some generics when calling a function with multiple generics

See original GitHub issue

Right now in TypeScript it’s all or nothing when calling generic methods. You can either skip typing all the generics altogether and they will be inferred from the context (if possible), or you have to manually (re)define all of them. But the reality isn’t black and white, there are also shades of gray, where we can infer types for some of the generic parameters, but not others. Currently those have to be unnecessarily verbose by forcing the programmer to explicitly restate them.

Take a look at these 3 cases:

Case 1 - everything can be inferred - no need to call the method with <> definition:

function case1<A, B, C>(a: A, b: B, c: C): A {}

example(1, '2', true);

Compiler knows that: A is number B is string C is boolean


Case 2 - nothing can be inferred, so we need to state what A, B and C should be, otherwise they’ll default to {}:

function case2<A, B, C>(): A {}

example<number, string, boolean>();

Case 3 - the one that’s interesting to this feature request - some can be inferred, some can’t:

function case3<A, B, C>(b: string, c: boolean): A {}

// incorrect type of A - left unspecified:
example('thing'); 

// correct, but unnecessarily verbose - we already know that 'thing' is a string and true is a bool
example<number, string, boolean>('thing', true);

Now, typing string, boolean in the above example isn’t a big deal, but with complex scenarios, say with a method using 5 generics, where you can infer 4 of them, retyping them all seems overly verbose and prone to error.

It would be great if we could have some way to skip re-typing the types that can automatically be inferred. Something like a special auto or inferred type, so we could write:

example<number, auto, auto>('thing', bool);

Or maybe even, if we only want to specify those up to a certain point:

example<number>('thing', bool);

The above “short-hand” notation could perhaps be different to account for function overloads with different number of generics.

Having such a feature would solve newcomers encountering problems such as this one: http://stackoverflow.com/questions/38687965/typescript-generics-argument-type-inference/38688143

Issue Analytics

  • State:open
  • Created 7 years ago
  • Reactions:582
  • Comments:70 (19 by maintainers)

github_iconTop GitHub Comments

104reactions
jednanocommented, Jun 29, 2020

I can’t tell you how many times I’ve needed this feature and had to do something super ugly to dodge the non-existence of it (e.g., creating a wrapper function that has a subset of the generic types).

49reactions
dhoulbcommented, Jan 8, 2020

@lukescott

I think what you suggested would be too much of a break from the current way it works (i.e. you must specify all generics or none, no middle ground).

But as a solution I loved the suggestion about using the = infer syntax as a default value. I think the resulting syntax would be super clean.

export function mapEnum<D extends string, S extends string = infer>(value: S, object: {[K in S]: D}): D  {
	return object[value]
}

Additionally this could provide some protection if the value could not be inferred (rather than the generic defaulting to any which is probably never what you want).

export function mapEnum<D extends string, S extends string = infer>(value: S | null, object: {[K in S]: D}): D  {
	return object[value]
}

mapEnum<number>(null, {}); // TS error "cannot infer generic S" or similar.

Another thought I’d had was an always inferred generic using infer S syntax, that would actually stop you setting it manually. I might be trying to push this too far now, but I think it’d round out this set of functionality nicely.

// Either this syntax.
export function mapEnum<D extends string, infer S extends string>(value: S, object: {[K in S]: D}): D  {
	return object[value]
}

// Or this syntax (I can't decide).
export function mapEnum<D extends string>(value: infer S extends string, object: {[K in S]: D}): D  {
	return object[value]
}

mapEnum<number, "b">("a", {}); // TS error "generic S cannot be set manually, it must be inferred"
Read more comments on GitHub >

github_iconTop Results From Across the Web

typescript - How to skip define type on multiple generics class
You can do this by using a pair of interfaces and a variable, following the pattern used to define Array in lib. d....
Read more >
2 | Multiple Generic Parameters in TypeScript - YouTube
You can use multiple generic types in a function. This video shows how this works and how to name the generic type variables....
Read more >
Documentation - Generics - TypeScript
This allows us to traffic that type information in one side of the function and out the other. We say that this version...
Read more >
Exploiting Generics in TypeScript - Visual Studio Magazine
This method calls a generic function, specifying the data type to be ... a generic function is because you have some code that...
Read more >
Generics in Go – everything you should know before you start
The constraint allows any type satisfying the interface, ... The latter applies to generic types/functions with multiple type parameters.
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