I am trying to do a generic react form reducer. For that "Value" must have the type of T by "name". Im not sure to be comprehensive so here is an example that will be clearer:
Example:
type RandomObject = { test1: number, test2: string, test3: string[] }
type ActionChangeInput<T> = {
name: keyof T
value: typeof T["name"] // Get type of name
}
I want value to be a number because value of name is "test1" and "test1" type is number.
const a: ActionChangeInput<RandomObject> = {
name: "test1", // type is "test1" | "test2" | "test3"
value: 12931 // Expect number here
}
Sorry if it's not clear but it's hard to explain something I don't understand (that's why im here).
CodePudding user response:
What you want is for ActionChangeInput<T>
to resolve to a union of all possibilities. You can do that with a mapped type that maps over each property of T
and creates type that pairs name and value types for just that property.
Something like:
type ActionChangeInput<T> = {
[K in keyof T]: {
name: K
value: T[K]
}
}[keyof T]
This maps over each property in T
with [K in keyof T]
, and creates an object type for each combination of name
as K
and value as T[K]
.
You then index that resulting object by it's own keys to get a union of its values.
With the RandomObject
type, that should resolve to:
type RandomObject = { test1: number, test2: string, test3: string[] }
type Test = ActionChangeInput<RandomObject>
/*
| { name: 'test1', value: number }
| { name: 'test2', value: string }
| { name: 'test3', value: string[] }
*/
So any valid value of that type must have a name
and value type that match in that list of unions.
The rest now behaves as you would expect:
type RandomObject = { test1: number, test2: string, test3: string[] }
// fine
const a: ActionChangeInput<RandomObject> = {
name: "test1",
value: 12931,
}
// error
const b: ActionChangeInput<RandomObject> = {
name: "test2",
value: 12931, // Type 'number' is not assignable to type 'string'.(2322)
}