Search code examples
typescriptobjectoopdynamic

Modify an object in a class with a method


I'm trying to describe a fairly simple method in TypeScript.

The method must allow any object type of the data attribute to modify its data. In other words, we can modify, add or remove data in the data type, and dynamically, TypeScript allows us to do this by associating each type well. If the value to be modified is a number, then it leaves only numbers to be filled in. (I'm not sure that's clear).

Here is a simple example:

interface BackgroundProperties {
    backgroundColor: string;
    paddingTop: number;
    paddingBottom: number;
    paddingLeft: number;
    paddingRight: number;
    hasShadow: boolean;
    shadowBlur: number;
    shadowColor: string;
    shadowOffsetX: number;
    shadowOffsetY: number;
}

const o = new Obj();
o.setBackgroundProperty("backgroundColor", "#000"); // Needs to be a string
o.setBackgroundProperty("backgroundColor", 0); // Got an Error
o.setBackgroundProperty("paddingBottom", 10); // Needs to be a number
o.setBackgroundProperty("paddingBottom", "10"); // Got and error

For the moment, I've the following code:

interface BackgroundProperties {
    backgroundColor: string;
    paddingTop: number;
    paddingBottom: number;
    paddingLeft: number;
    paddingRight: number;
    hasShadow: boolean;
    shadowBlur: number;
    shadowColor: string;
    shadowOffsetX: number;
    shadowOffsetY: number;
}

class Obj {
  data: { background: BackgroundProperties };

  constructor() {
    this.data = {
     background: {
          backgroundColor: "#ABB8C3",

          hasShadow: true,
          shadowColor: "rgba(0,0,0,0.55)",
          shadowBlur: 68,
          shadowOffsetY: 12,
          shadowOffsetX: 0,

          paddingBottom: 56,
          paddingTop: 56,
          paddingLeft: 56,
          paddingRight: 56
      }
    }
  }

  public setBackgroundProperty<O extends BackgroundProperties, K extends keyof O>(key: K, value: O[K]) {
        if (String(key).endsWith('Color') && typeof value === 'string' ? value : '')
            throw new Error(`The ${key.toString()} background color value is not a hexadecimal color!`);


        this.data.background[key] = value;
        return this;
  }
}

But, I have an error on this line: this.data.background[key] = value;. The error is:

Type 'K' cannot be used to index type 'BackgroundProperties'.

I've been looking for solutions on the internet, but I can't find where it comes from.

Here is an example reproduced on TypeScript Playground.


Solution

  • Since you are declaring that O extends BackgroundProperties, there is no guarantee that K is a valid key of BackgroundProperties itself. It could be a key of the extended type. But data.background is of type BackgroundProperties, and can only accept keys of that type.

    To fix the issue, you could change the signature like so:

    public setBackgroundProperty<K extends keyof BackgroundProperties>(key: K, value: BackgroundProperties[K]) {