I’m wondering how to correctly infer the 2nd and 3rd type arguments of my function.
Suppose a simple interface:
interface ISome {
a: string;
b?: {
c: string;
};
}
The following works:
function pathBuilder<
K1 extends keyof ISome,
K2 extends keyof NonNullable<ISome[K1]>
>(p: K1, p2?: K2) {
let res = String(p);
if (p2) { res += "." + p2; }
return res;
}
const pathTest = pathBuilder("b", "c"); // ---> "b.c" and intellisense works on parameters
But I need to generalize the function to work for a caller-defined type instead of ISome
(I don’t want to pass an object instance to specify the type).
The following does not work:
function pathBuilder<
T,
K1 extends keyof T,
K2 extends keyof NonNullable<T[K1]>
>(p: K1, p2?: K2) {
let res = String(p);
if (p2) { res += "." + p2; }
return res;
}
const pathTest = pathBuilder<ISome>("b", "c"); // ERROR: Expected 3 type arguments, but got 1.ts(2558)
It seems that the 2nd and 3rd template arguments of the function don’t infer from the first, but it should because when I directly specified the type as T = ISome
, it worked.
I’m not sure if there is some language keyword to make it work but the type parameter should work exactly for that: specifying an unknown type.
EDIT
Actually I found this way, but it requires extra coding I’d like to avoid if possible:
function pathBuilder<T>() {
return <
K1 extends keyof T,
K2 extends keyof NonNullable<T[K1]>>(p: K1, p2?: K2) => {
let res = String(p);
if (p2) { res += "." + p2; }
return res;
};
}
const pathTest = pathBuilder<ISome>()("b", "c");