Home > database >  Typescript Have the type of the property from an object
Typescript Have the type of the property from an object

Time:12-03

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)
}

See Playground

  • Related