Reputation: 2483
How to make a required type parameter Y
in a function work together with another type parameter K
where the latter is only used as a key in a record R = {a: 'aaa', b: 'bbb'}
lookup and is not supposed to be explicitly provided? The type parameter K
should be inferred from the value of the first parameter k
of the funciton foo
. I want then to use K
to lookup a type in R
so that I can use it for the other params of the function.
To allow for only the first type parameter Y
to be required, the K
param needs to have a default value. But this default value then breaks the inference of R[K]
when instead of inferring based on the value of k
i.e. R[typeof k]
to "aaa"
if k
was "a"
, it uses the default of K
i.e. R[keyof R]
resolving to a union of all types in the record R
i.e. "aaa" | "bbb"
disregarding k
.
Is it possible to have type inferrence for y: R[keyof K]
where K
is resolved from the value of k
without explicitly passing K
, but still allow for the required type param Y
?
type R = {
a: 'aaa',
b: 'bbb',
}
type Foo = <
Y,
K extends keyof R = keyof R,
>(k: K, f: (x: R[K], y: Y) => any) => any
const foo: Foo = (x, y) => null
// With no type params Rec[K] is correctly inferred from K: 'a'
foo('a', (x, y) => null) // x: "aaa"; y: unknown
// When passing the Y type param, Rec[K] ignores the K: 'a'
foo<number>('a', (x, y) => null) // x: "aaa" | "bbb"; y: number
// When passing both Y and K it works
foo<number, 'a'>('a', (x, y) => null) // x: "aaa"; y: number
I could only make it work by currying the function so each type parameter belongs to a separate function:
type FooCurried = <K extends keyof R = keyof R>(k: K) =>
<Y>(f: (x: R[K], y: Y) => any) =>
any
const fooCurried: FooCurried = x => y => null
fooCurried('a')<number>((x, y) => null) // x: "aaa"; y: number
Upvotes: 0
Views: 348
Reputation: 2483
Found a fairly similar question where the accepted answer says that this can only be done by currying the function, as I did in the example.
Upvotes: 0