tgmerritt
tgmerritt

Reputation: 744

How to declare the type of this variable within map()

Here is the function in question:

  const getCountryLangCode = (countryCode: string) => {
    const filtered = Object.entries(config.languages)
      .map(([key, language]) => {
        if (language.code.split('-')[1] === countryCode) {
          return language.code
        }
      })
      .filter(item => item)
  
    const langCode = filtered[0]
  
    return langCode
  }

The problem is that 'language' within the map() function is type = unknown, and when I try to build my React app it is failing to build due to this type Object is of type 'unknown'. TS2571

I've tried every version of the typing syntax that I can think of to feed 'any' type to 'language' but I'm doing it wrong.

What's the proper way to declare that language should be type == any ?

Upvotes: 1

Views: 3805

Answers (2)

Linda Paiste
Linda Paiste

Reputation: 42208

Declare Types Higher-Up

You always want to declare the type higher-up in the chain when you can. You are asking to "declare the type of this variable within map()" but you want to declare the type of the config variable. Having a proper type on the config.languages object will allow Typescript to infer the types of Object.entries, .map(), and .filter() on its own.

config is an object with a property languages. That languages property is an object where each value is an object with a property code which is a string. We use the Typescript type Record<Keys, Values> when we have an object where all values are the same type.

interface MyConfig {
  languages: Record<string, {code: string}>
}

Writing the Function

There may be other properties that you want to include to help out other functions, but that's all we need to know here.

As pointed out by @Andreas, .map() is not the ideal function here. If you wanted to find all matches you would use .filter() directly on the entries. Since you only want to first you should use .find(). You don't look at the key at all so you can use Object.values instead of Object.entries.

const match = Object.values(config.languages).find(
  language => language.code.split('-')[1] === countryCode
);
return match?.code;

If config has type MyConfig then the variable languages in the find() callback will automatically get the type { code: string } because Typescript knows the value type of the config.languages object.

We use the optional chaining ?. because find is not guaranteed to find a match, so match might be undefined. Our function returns string | undefined.

Typescript Playground Link

Upvotes: 1

Evgeny Klimenchenko
Evgeny Klimenchenko

Reputation: 1194

To answer your question to put type on Object.entries you do it like this

...
const filtered = Object.entries<{ code: string }>(config.languages)
      .map(([key, language]) => {
...

see there <YourType> before ( and after entries. This way you will put specific type on incoming entries parameter, in your case config.languages

Upvotes: 1

Related Questions