pzaenger
pzaenger

Reputation: 11984

Store instances of a generic class in a map while keeping them typed correctly

In TypeScript I would like to store instances of a generic class (here class Foo) in a Map.

However, I do not get the desired results since the map values are (obviously) not typed correctly since the use of any. Is there any way to get it done?

I am not sure about using Record or type aliases might be worth a look.

class Foo<T> {
  t: T;
}

class Bar {

  // Use of any because I am not sure about the right way
  map: Map<string, any> = new Map();
}

const bar = new Bar();

bar.map.set('numberEntry', new Foo<number>());
bar.map.set('stringEntry', new Foo<string>());

const n = bar.map.get('numberEntry').t;
const s = bar.map.get('stringEntry').t;

console.log(typeof n); // undefined; should be 'number'
console.log(typeof s); // undefined; should be 'string'

Please let me know if further details are needed.

Upvotes: 0

Views: 329

Answers (1)

Maciej Sikora
Maciej Sikora

Reputation: 20162

First of all typeof n is runtime check, and we have here runtime issue, as our Foo instances have no values in field t. There is no assignment of this field in the code. new Foo<number>() creates Foo instance with undefined t field. We need to pass somehow t. We can fix it in the following way:

class Foo<T> {
  t: T;
  constructor(t: T) {
    this.t = t;
  }
}

Now about typying and using any.

If we use Set then it is not possible to match key of the set with particular value type. We can say that this set have some possible types, in this example it would be:

Map<string, Foo<string | number>> = new Map();

Full working code

So we are saying in our Map we store values of Foo with either string or number fields.


BTW. If we want to have key -> value type relation we should use POJO:

const map: {
  numberEntry: Foo<number>;
  stringEntry: Foo<string>;
} = {
  numberEntry: new Foo(1),
  stringEntry: new Foo("a")
};

Upvotes: 2

Related Questions