Home > other >  Using TypeScript Enum as object property keys
Using TypeScript Enum as object property keys

Time:09-23

I'm trying to use Enum values as the keys for an object, expecting this to preserve the type when I get the value, but I'm getting Element implicitly has an 'any' type because expression of type 'string' can't be used to index type.

export enum TaskType {
  Classification = 'classification',
  Extraction = 'extraction'
}
const comparisons: { [name in TaskType]: Function } = {
  'classification': () => false,
  'extraction': () => false
}
for (const taskType in comparisons) {
  // I expect func to be of type Function, but I get a TypeScript error:
  // Element implicitly has an 'any' type because expression of type 'string' can't be used to index type
  const func = comparisons[taskType] 
}

I've tried using const func = comparisons[taskType as keyof TaskType] but this doesn't work either.

CodePudding user response:

taskType in for-in is a string type, you cannot map it with an enum type under comparisons.

You can cast it to TaskType enum by as like the below code snippet instead.

Side note, instead of using a static string key for comparisons, you can use enum keys directly on it.

export enum TaskType {
  Classification = 'classification',
  Extraction = 'extraction'
}
const comparisons: { [name in TaskType]: Function } = {
  [TaskType.Classification]: () => false,
  [TaskType.Extraction]: () => false
}
for (const taskType in comparisons) {
  const func = comparisons[taskType as TaskType] //cast it to an enum type
}

Playground

CodePudding user response:

As mentioned in the another answer, you can use to cast the key which is fine.

However I've got an alternative in your case by switching using Object.keys(comparisons), but unfortunately with the current definition of ObjectConstructor, it doesn't support to infer the correct type as well.

interface ObjectConstructor {
  //... 
  keys(o: object): string[]
  keys(o: {}): string[]
}

But there's a solution to override it. Let's do following steps:

  • Create your typings/override.d.ts with following data and put it as part of include in your configuration:
// typings/override.d.ts
type ObjectKeys<T> = T extends object
  ? (keyof T)[]
  : T extends number
  ? []
  : T extends Array<any> | string
  ? string[]
  : never;

interface ObjectConstructor {
  keys<T>(o: T): ObjectKeys<T>;
}

// tsconfig.json
{
  // ...
  include: [..., 'typings']
}

Now, you can re-write your code with Object.keys way:

Object.keys(comparisons).forEach((k) => {
  // `k` is now `TaskType` type
});
  • Related