3

I am attempting to use Javarome's answer to a previous TypeScript question regarding how to use an object in an enum:

class Material {
  public static readonly ACRYLIC = new Material(`ACRYLIC`, `AC`, `Acrylic`);
  public static readonly ALUM = new Material(`ALUM`, `AL`, `Aluminum`);
  public static readonly CORK = new Material(`CORK`, `CO`, `Cork`);
  public static readonly FOAM = new Material(`FOAM`, `FO`, `Foam`);

  // private to diallow creating other instances of this type.
  private constructor(
    public readonly key: string,
    public readonly id: string,
    public readonly name: string
  ) {}

  public toString(): string {
    return this.key;
  }
}

Unfortunately, I am running into an issue later in the code when I attempt to use bracket-syntax (because it's in a for-of loop):

const materials: string[] = [`ACRYLIC`, `FOAM`];
for (const materialKey of materialsArray) {
  const material: Material = Material[materialKey];
  // ...
}

That pops up a huge TS error [TS(7053)] with the following message:

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'typeof Material'.

No index signature with a parameter of type 'string' was found on type 'typeof Material'.ts(7053)

I have been Googling for hours but have found nothing that helps. Is there any way to reference this "enum" using bracket-syntax?

Community
  • 1
  • 1
Sturm
  • 689
  • 2
  • 23
  • 52

1 Answers1

2

The issue with this code is exactly:

const materials: string[] = [`ACRYLIC`, `FOAM`];

There is no relation between possible properties of Material static class and a list of strings. The key to the problem is to specify in type that the list which we have is a list of only allowed properties which have values as Material type.

It can be achieved by Exclude type utility. Take a look at below example:

type MaterialKeys = Exclude<keyof typeof Material, 'prototype'>;
const materialsArray: MaterialKeys[] = [`ACRYLIC`, `FOAM`];
for (const materialKey of materialsArray) {
  const material: Material = Material[materialKey];
  // ...
}

For more informations: Exclude<keyof typeof Material, 'prototype'>; will take all keys of Material type and exclude from it the prototype, so we will in result have all static fields, and that is what we want though.

Maciej Sikora
  • 19,374
  • 4
  • 49
  • 50