I'm struggling on this for a long time,
function processEntity<
T extends Record<string, unknown>,
U extends keyof T = keyof T,
V extends Pick<T, U> = Pick<T, U>
>(arg: {keys: Array<U>; resolver: (doc: V) => void}) {
arg.resolver(...)
}
type Cat = {
name: string
age: number
}
processEntity<Cat>({
keys: ['name'],
resolver: (doc) => {
// doc.name should exists
// doc.age should be undefined
},
})
As you can see above, there is a function processEntity
which accepts an object as the argument.
What I want is to make type of argument of arg.resolver
depends on type of arg.keys
. Say if I pass ['name']
to keys:
field, then when doc.age
should not be accessable because 'age'
was missed in keys
field.
I've looked at some questions listed below but they does not help, so please help :pray:
- How to define a function's argument type dependent on string argument in Typescript?
- Typescript make one parameter type depend on the other parameter
- Declaring dependent argument types for optional arguments with conditional types
- Typescript. Correctly typing function parameter that depends on property in the same object literal
CodePudding user response:
You are very close. The main problem is that Typescript does not support partial inference in functions. This means you can either specify all type parameters, or you can let typescript infer all of them, but you can't specify some and let TS infer the others. This means you can't specify T
and let TS infer U
.
There can be several solutions to this. One is to use function currying to specify T
in a first call and let TS infer U
in the second call:
function processEntity<
T extends Record<string, unknown>>() {
return function <
U extends keyof T = keyof T
>(arg: { keys: Array<U>; resolver: (doc: Pick<T, U>) => void }) {
// arg.resolver(...)
}
}
Or you could add a dummy field to have an inference location for T
, the value of which does not really matter:
function processEntity<
T extends Record<string, unknown>,
U extends keyof T = keyof T,
>(arg: { type: T, keys: Array<U>; resolver: (doc: Pick<T, U>) => void }) {
//arg.resolver(...)
}