0

i have googled and found kinda same issues but as i' new to TS i couldn't implement to my case. So

In my nextjs + ts app, i enabled internalization for 4 languages. The content is static and comes from backend.


This is the shape of all of my static content

field: {
 en: "",
 ru: "",
 uz: "",
 oz: ""
}

and this is a simplified demonstration of how i'm showing them depending on the site language:

const static_content = {
 title:{
  en: "Main title",
  ru: "Основное название",
  uz: "Bosh sahifa",
  oz: "Бош саҳифа"
 }
 ...
}

import {useRouter} from 'next/router'
const router = useRouter()

static_content.title[router.locale] // Type 'undefined' cannot be used as an index type. ts(2538)

i tried:

router.locale && static_content.title[router.locale]

but in this case it says:

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ en: string; ru: string; uz: string; oz: string; }'.
  No index signature with a parameter of type 'string' was found on type '{ en: string; ru: string; uz: string; oz: string; }'.ts(7053)


Data comes from backend looks like this:

{
 title_en: "",
 title_ru: "",
 title_uz: "",
 title_oz: "",
 ...
}

and this is how i'm displaying it

interface dataType {
 title_en: string
 title_ru: string
 title_uz: string
 title_oz: string
}

const data: dataType = await fetchData()

data['title_'+router.locale] // error ts(7053)

error ts(7053):

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'dataType'.
  No index signature with a parameter of type 'string' was found on type 'dataType'.ts(7053)

The project was already finished in javascript, i just wanted to convert to typescript. This is the only type error i couldn't solve because i'm new to ts and this only error exists in my 20 pages 2-4 per page so i would like to have simply solution.

Thank you in advance!

A.Anvarbekov
  • 955
  • 1
  • 7
  • 21
  • 1
    Does this answer your question? [TypeScript - Element implicitly has an 'any' type because expression of type 'string' can't be used to index type](https://stackoverflow.com/questions/57438198/typescript-element-implicitly-has-an-any-type-because-expression-of-type-st) – juliomalves Jan 23 '22 at 15:59

1 Answers1

0

Can we try and declare an interface for representing static content like so...

interface StaticContent {
  title: { [key: string]: string };
}

and then assign this type to the incoming data like so...


const static_content: StaticContent = {
  title: {
    en: "Main title",
    ru: "Основное название",
    uz: "Bosh sahifa",
    oz: "Бош саҳифа"
  }
  // ...
}

and then we can easily do

router.locale && static_content.title[router.locale]

Do we have any problem with this approach in your codebase?

Nalin Ranjan
  • 1,728
  • 2
  • 9
  • 10
  • Yes, this is working for `static content`, thank you. But what can i do for `dynamic content`, most of my content is dynamic? And is it ok to do this `title[router.locale!]` instead of `router.locale && title[router.locale]` as it is less code? – A.Anvarbekov Jan 23 '22 at 13:16
  • You can read about [Index Signatures](https://www.typescriptlang.org/docs/handbook/2/objects.html#index-signatures). Very useful for accessing dynamic data and very suitable for the cases that you have. – Nalin Ranjan Jan 23 '22 at 13:47
  • `{ [key: string]: string }` too is an indexing signature where the type of the key is `string` and the value is also `string`. For complex types, the type of value can be specified accordingly. – Nalin Ranjan Jan 23 '22 at 13:49
  • Th only problem is that indexing signature doesn't allow `undefined` value for accessing. To prevent from an error in such cases at runtime, it's better to do a condition check and then try and access. `router.locale &&` does that condition check, preventing erroneous access at runtime. – Nalin Ranjan Jan 23 '22 at 13:51
  • Is the answer good enough for you, or else let me know if you want it adjusted for some specific condition(s). – Nalin Ranjan Jan 23 '22 at 13:51
  • i tried this `[title_uz:string]:string ...` idk if it is correct, no error, but i seem to be losing type definition. if i do `data['title_u']` it didn't give error and no autocompletion. would appreciate a real showcase – A.Anvarbekov Jan 23 '22 at 14:24
  • You have to specify `index signature` like `{ [key: string]: string }`. I don't think `[title_uz: string]: string` will be a valid `index signature`. – Nalin Ranjan Jan 23 '22 at 14:28
  • Try `const dynamic_data: { [key: string]: string } = await getDynamicData();`. Then we should be able to do `dynamic_data[someStringKey]`.. – Nalin Ranjan Jan 23 '22 at 14:31
  • Like..... `const data: { [key: string]: string } = await fetchData()`. – Nalin Ranjan Jan 23 '22 at 14:36
  • yeah, it was my only choice i did so but i lost type definition... I mean it is not checking for existence. Anyways i am accepting your answer thanks i learnt smth, i'm better learn index signature more – A.Anvarbekov Jan 23 '22 at 15:48
  • Depending upon your usage you can use either. So when you have to access based on a key whose value will be known at runtime, use the `index signature` type, and when you want to access with keys from your interface type, use `const dynamic_data: datatype = somedata`. – Nalin Ranjan Jan 23 '22 at 15:52