user10471818
user10471818

Reputation:

Index signature types

I am having troubles trying to write types for the following:

type Language = 'en' | 'nl';

interface CacheObject {
  [key: string | number | Language]: string;
}

const cache: CacheObject = {};

export const init = (dir: string): Promise<void> =>
  fsPromises.readdir(dir).then(files =>
    files
      .filter(files => files.endsWith('.json'))
      .forEach(async file => {
        cache[file.slice(0, -5)] = await import(`${dir}/${file}`);
      })
  );

export const translate = (lang: Language): any => (key: string) =>
  key.split('.').reduce((acc, val) => acc[val], cache[lang]);

The problems are as follow

const cache: CacheObject
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'CacheObject'.
  No index signature with a parameter of type 'string' was found on type 'CacheObject'.
const cache: CacheObject
Element implicitly has an 'any' type because expression of type 'Language' can't be used to index type 'CacheObject'.
  Property 'en' does not exist on type 'CacheObject'.

Could somebody help me pointing me in the right direction?

Upvotes: 0

Views: 117

Answers (1)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249506

You are ignoring another error you are getting: An index signature parameter type must be 'string' or 'number' (There might be another bug in TS where this error might be suppressed by other errors, when testing your code there was a time when the error was missing but appeared after making some non consequential changes to the code. Play with error)

If you want to use Languages to add some known elements to the type to your type you will need to use a mapped type in an intersection with a type that contains the index signature:

type CacheObject = {
  [key: string]: string;
  [key: number]: string;
} & Partial<Record<Language, string>>

Play

If you just had the index signatures to keep the compiler quiet about indexing with strings, but the object can only ever contain the languages you could consider just casting the indexing expression:

type CacheObject = Partial<Record<Language, string>>
cache[file.slice(0, -5) as Language] = await import(`${dir}/${file}`);

Play

Upvotes: 1

Related Questions