nolan
nolan

Reputation: 467

How to best describe this code using TypeScript?

Here is an object with several different key and value, and each props of value differ from each other, how to best describe this object using TypeScript? Especially the setValue method, how to limit type of the creatureType, prop and value?

 const object = {
      john: {
        name: '',
        age: 18
      },
      alien: {
        height: 20,
        power:100,
      },
      setValue(creatureType) {
        const self = this
        return function (prop) {
          return function (value) {
            self[creatureType][prop] = value
          }
        }
      }
    }

Upvotes: 2

Views: 98

Answers (1)

jcalz
jcalz

Reputation: 328658

Your setValue() method will need to be generic if you want it to place strong restrictions on which properties and values go with which, uh, "creature type". Because the type of the object's setValue() method will be dependent on the type of the other properties of object, the compiler will give up trying to infer types for it; it's too circular for something that isn't a class. Either you could manually annotate all the types, which would be annoying, or you could split object into two pieces, say plainObject holding just the data, and then merge in the setValue() method which will be dependent on the type of plainObject, like this:

const plainObject = {
    john: { name: '', age: 18 },
    alien: { height: 20, power: 100 }
}
type PlainObject = typeof plainObject;

const object = {
    ...plainObject,
    setValue<K extends keyof PlainObject>(creatureType: K) {
        const self: PlainObject = this;
        return function <P extends keyof PlainObject[K]>(prop: P) {
            return function (value: PlainObject[K][P]) {
                self[creatureType][prop] = value;
            }
        }
    }
}

And you can verify that the compiler behaves as you want:

object.setValue("john")("age")(19); // okay
object.setValue("alien")("height")("pretty tall"); // error!
// "pretty tall" isn't numeric --> ~~~~~~~~~~~~~
object.setValue("john")("power")(9000); // error!
// "power" is wrong --> ~~~~~~~
object.setValue("elaine")("name")("elaine"); // error!
// "elaine"? -> ~~~~~~~~

Okay, hope that helps; good luck!

Link to code in Playground

Upvotes: 3

Related Questions