4
votes

For my new small project I decided to go with typescript for a reason no better than making myself feel like programming c on remarkable steroids and apparently I'm paying the price.

I have an interface, right

export default interface DataObject {
  [key: string]: any
};

Which is supposedly allowing me to define objects with string keys and whatever values. Then I'm implementing it

import DataObject from "./data-object";

export default class Model implements DataObject {

  constructor(data: DataObject = {}) {
    Model.fill(this, data);
  }

  static fill(model: Model, data: DataObject) {
    for (let prop in data) {
      model[prop] = data[prop];
    }
  }
}

Now I'm getting this error

Element implicitly has 'any' type because type 'Model' has no index signature

on this line

      model[prop] = data[prop];

But if I modify my model to include the signature

import DataObject from "./data-object";

export default class Model implements DataObject {

  [key: string]: any;

  ...
}

Then there is no error.

Why is the interface signature not having effect on my class?

1

1 Answers

2
votes

I think interfaces don't have influence to the implementation. If you change it to a class and extends it than it works as expected. That’s because you can the index implement in another way, like properties, see the example (in the Playground).

interface DataObject {
    foo: any;
    bar: any;
    [key: string]: any;
};

class Model implements DataObject {

    private _bar: string = null;
    public get bar(): string {
        return this._bar;
    }
    public set bar(value: string) {
        this._bar = value;
    }

    constructor(data: DataObject = {}) {
        this.foo = "bar"; // error
        this.bar = "foo"; // no error
        Model.fill(this, data);
    }

    static fill(model: Model, data: DataObject) {
        for (let prop in data) {
            model[prop] = data[prop]; // error
        }
    }
}

class DataObject2 {
    foo: any;
    bar: any;
    [key: string]: any;
};

class Model2 extends DataObject2 {

    constructor(data: DataObject2 = { foo: "", bar: "" }) {
        super();
        this.foo = "bar"; // no error
        this.bar = "foo"; // no error
        Model2.fill(this, data);
    }

    static fill(model: Model2, data: DataObject2) {
        for (let prop in data) {
            model[prop] = data[prop]; // no error
        }
    }
}