Reputation: 79
I am trying to setup a generic where the parameter is the key of another object. I can accomplish this using extends keyof
when both types are parameters are to the function.
However when the type providing the list of keys is not an argument, just a generic type, typescript requires both generic types to be set.
Consider the following code:
interface Bar {
z: string;
t: number;
}
declare function foo1<T extends keyof Bar>(x: T)
let t1 = foo1('z');
declare function foo2<K, T extends keyof K>(x: T)
let t2 = foo2<Bar>('t');
declare function foo3<T>(x: T)
let t3 = foo3<keyof Bar>('t');
Function foo2
fails since the second type T
is not specified. However I feel like TS should be able to infer the correct typings without an explicit second type.
foo3
is my workaround, but isn't as nice to work with, is it possible to have typescript perform this inference, or will this be a feature request / bug report to the TS team?
Upvotes: 3
Views: 8836
Reputation: 3199
You are close with foo2
. Here is what it's supposed to be to make it work.
declare function foo2<T, K = keyof T>(x: K)
let t2 = foo2<Bar>('t');
Instead of expecting a new generic type parameter, you can assign one to a type (in this case the type of T
).
It's also possible to directly assign the paramaters type to the keyof
the given generic type T
.
declare function foo4<T>(x: keyof T);
let t4 = foo4<Bar>('t');
Upvotes: 5
Reputation: 328142
There is already an outstanding suggestion for partial inference of type parameters (without using defaults) at Microsoft/TypeScript#14400. For now, you can't do that. Instead, I will give you a workaround that I often suggest in cases like this: curried functions.
declare function curriedFoo<B>(): <T extends keyof B>(x: T)=>any;
let t4 = curriedFoo<Bar>()('t'); // okay
The no-argument function curriedFoo()
takes a type parameter B
(I can't use K
for anything but a key, sorry), and returns a function of the type you really want, narrowed to only accepting a T extends keyof B
parameter (here's where I'd want to use K
, but never mind).
It's a bit clumsy but it gets the job done. Hope that helps; good luck!
Upvotes: 2