Search code examples
typescript

Variable as property name of a type in a returned function


I'm trying to create a generic method that returns a function whose type must depend on the first method's parameter, to get some type safety.

I've seen similar questions, but none seem to match my case.

Here is what I'm trying to achieve:

myMethod(fieldName: string) {
  return (val: {[fieldName: string]: number}) => {
    val[fieldName] // do Stuff where I know val[fieldName] is a number
  }
}

So that elsewhere, I can do:

const a = {
  pname: 32
  other: 'asasd'
}
const b = {
  pname: 'aaa'
  other: 'asasd'
}

myMethod('pname')(a); // compiler/IDE should say it's ok
myMethod('pname')(b); // compiler/IDE should say b is incompatible because b.pname is not a number

That above doesn't work, the fieldName in {[fieldName: string]: number} is not interpreted as the parameter fieldName of myMethod. The compiler interprets it as it requires all properties of a or b to be numbers, which is not what I want. I just want to force a.pname to be number.

Is that possible?


Solution

  • You should make the object as a generic parameter:

    Playground

    function myMethod<K extends string, T extends {[P in K]: number}>(fieldName: K) {
      return (val: T) => {
        val[fieldName] // do Stuff where I know val[fieldName] is a number
      }
    }
    
    const a = {
      pname: 32,
      other: 'asasd'
    }
    const b = {
      pname: 'aaa',
      other: 'asasd'
    }
    
    myMethod('pname')(a); // compiler/IDE should say it's ok
    myMethod('pname')(b); // compiler/IDE should say b is incompatible because b.pname is not a number