1

I'm stumped, hopefully this simplified example explains it well enough:

I have a class instance holding data, and another composite class instance to render the data. The data class gives callbacks to UI class in order to get and set data properties. I'm stumped on the "set" too but I'll stick to "getVal" for now.

class Person {
  private _data: DataObj

  constructor() {
    this._ui = new PersonUI({
      getVal: (key) => this.getVal(key)
    })
  }

  getVal<T extends keyof DataObj>( key: T ) {
    return this._data[key]
  }
}

class PersonUI {
  constructor(arg: UIArg) {}
}

Typescript can infer the type of the _data value, but I don't know how to write an interface for UIArg that will keep that inferred type, all I could come up with was "any" ex:

interface UIArg {
  getVal: <T extends keyof DataObj>(key: T) => any
}

Is there a way to write the interface to keep the inferred type?

Bonus Q: is there a way to write the Person.p.setVal method to use the inferred type too? Ex:

setVal<T extends keyof DataObj>(key: T, val: any) {
  this._data[key] = val
}

1 Answer 1

1

You're looking for indexed access types. If you have a type T and a key type K extends keyof T, then the property at that key will have a value of type T[K]. In your case, DataObj is taking the role of T, and I will use K to represent the key type (which is more idiomatic than T)... so the value type in question is DataObj[K]:

interface UIArg {
    getVal: <K extends keyof DataObj>(key: K) => DataObj[K],
    setVal: <K extends keyof DataObj>(key: K, val: DataObj[K]) => void;
}

class Person {
    private _data: DataObj
    private _ui: PersonUI;
    constructor(data: DataObj) {
        this._data = data;
        this._ui = new PersonUI({
            getVal: key => this.getVal(key),
            setVal: (key, val) => this.setVal(key, val)
        })
    }

    getVal<K extends keyof DataObj>(key: K): DataObj[K] {
        return this._data[key]
    }

    setVal<K extends keyof DataObj>(key: K, val: DataObj[K]) {
        this._data[key] = val
    }

}

This compiles with no errors.

Playground link to code

Sign up to request clarification or add additional context in comments.

1 Comment

This is exactly what I was looking for! Thank you! Didn't know syntax like DataObj[K] was even possible on an interface

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.