I'm on a quest to deduce the type for every spread argument of my type function.
Suppose I have two fields defined as follows.
type Field<T> = { value: T, name: string }
const field1 = { value: 12, name: 'age' }
const field2 = { value: 'foo', name: 'nickname' }
and I wish to pass these fields as spread arguments to the following function, which would be invoked like this
useForm('registration', field1, field2)
My attempt involved using conditional type inference based on the official documentation, which did address the issue to some extent
type InferredFields<T> = T extends { value: infer V }[]
? Record<string, Field<V>>
: never
const useForm = <T extends Field<unknown>[]>(name: string, ...args: T) => {
const fields: InferredFields<T> = args.reduce(
(res, field) => ({
...res,
[field.name]: field.value,
}),
{} as InferredFields<T>,
)
return {
name,
fields
}
}
const form = useForm('bar', field1, field2)
The only problem I encountered is the difficulty in discriminating the union generated by the inferred value of the passed array generic based on the specific value being used.
type FieldValue<T> = T extends { value: infer V } ? V : never
// The issue arises from the return type of form being
// { fields: Record<string, string | number> }
// instead of accurately inferring the value type
const v1: FieldValue<typeof field1> = form.fields['age'].value // error
const v2: FieldValue<typeof field2> = form.fields['nickname'].value // error
https://i.sstatic.net/SnW4K.png
Any suggestions on how to correctly map the value types for each Field
type passed as an argument?