Home > Software engineering >  How do you reference an object interface's key in its value using Typescript?
How do you reference an object interface's key in its value using Typescript?

Time:05-19

I'm trying to create an object interface (transforms), that has keys which are properties of a generic object (T), so that the keys can map to a function that passes the property value of T specific to the key it was passed.

interface Options<T> {
  headers: (keyof T)[]
  filename: string
  items: T[]
  transforms?: Partial<{
    [field in T as keyof T]: (item: T[field extends keyof T ? field : never]) => string
  }>
}

As of now, item always resolves to never. I want it to be able to resolve to T[field] or rather T[keyof T] specific to the key it's attached to.


EDIT

Here is a better example of what I was trying to accomplish. I'm trying to make sure that the arguments passed to the functions in the transforms object, which have keys that are properties of T, have the correct type (T[keyof T]). In the corrected example below, color should be a string, and isTasty should be a boolean when passed as arguments in "transforms".

interface Food {
  isTasty: boolean
  color: string
}

interface Options<T> {
  headers: (keyof T)[]
  filename: string
  items: T[]
  transforms?: Partial<{
    ?
  }>
}

function Foo<T>({headers, filename, items, transforms}: Options<T>){
  return 'bar'
}

Foo({
  headers: ['isTasty', 'color'],
  filename: 'test',
  items: [{color: 'red', isTasty: true}] as Food[],
  transforms: {
    color: (color) => '#'   color,
    isTasty: (isTasty) => isTasty ? 'Yes' : 'No'
  }
})

fixed and working example

CodePudding user response:

You just want the transforms property to be a mapped type over the properties of T. Writing {[K in keyof T]: F<K>} will produce a new type with the same keys as T but whose properties are F<K> for each key type K. In your case, you want each property to be a function that accepts a value of the type corresponding to the property value of T at the key K. That is, a function that accepts a value of the indexed access type T[K]. Like so:

{ [K in keyof T]: (property: T[K]) => string }

Note that if you want to apply the Partial<T> utility type to it, you can write this more simply with the optional mapping modifier (?):

{ [K in keyof T]?: (property: T[K]) => string }

That gives you the following definition for Options<T>:

interface Options<T> {
  headers: (keyof T)[]
  filename: string
  items: T[]
  transforms?: {
    [K in keyof T]?: (property: T[K]) => string
  }
}

And then everything works as you want:

function foo<T>(o: Options<T>) { }

foo({
  headers: ['isTasty', 'color'],
  filename: 'test',
  items: [{ color: 'red', isTasty: true }],
  transforms: {
    color: (color) => '#'   color,
    isTasty: (isTasty) => isTasty ? 'Yes' : 'No'
  }
})

Playground link to code

  • Related