Using i18next to efficiently map an array of objects in TypeScript

I am currently converting a React project to TypeScript and using Packages like Next.js, next-i18next, and styled-components.

EDIT:

The information provided here may be outdated due to current versions of next-i18next.

Please check out: Typescript i18next does not satisfy the constraint 'string | TemplateStringsArray NextJS

For a quick example, consider the following code snippet:

{t<string, ItemProps[]>('document.items', {returnObjects: true}).map(({ name, description, index }) => (
  <li key={index}>
    <strong dangerouslySetInnerHTML={{__html: name}} />
    <Paragraph dangerouslySetInnerHTML={{__html: description}} />
  </li>
   )
)}

You can also view a working solution in this codesandbox.

Original Question:

In my language json file, I used an array of objects as shown below:

{
  "websites":
  [
    {
      "slug": "website-a",
      "name": "Website A"
    },
    {
      "slug": "website-b",
      "name": "Website B"
    }
  ]
}

To list all websites using i18next's { t }:

t('websites', {returnObjects: true}).map(({slug, name}) => ( ... ))

When using TypeScript, it showed an error for map:

Property 'map' does not exist on type 'string'.

To address this issue, I defined types and modified the code:

type websiteProps = {
  map: Function;
};

type itemProps = {
  slug: string;
  name: string;
};

t<websiteProps>('websites', {returnObjects: true}).map(({slug, name}: itemProps) => ( ... ))

This solution resolved the issue but I am open to suggestions for better alternatives. Any feedback is appreciated!

Thank you!

Answer №1

@cherryblossom's response is spot on - I am sharing a new answer to offer additional details.

Below is the defined type for the i18n t function (utilized in your code):

  <
    TResult extends TFunctionResult = string,
    TKeys extends TFunctionKeys = string,
    TInterpolationMap extends object = StringMap
  >(
    key: TKeys | TKeys[],
    options?: TOptions<TInterpolationMap> | string,
  ): TResult;

This function is generic and can accept TResult, Tkeys, and TInterpolationMap as parameters. When not explicitly specified, TResult defaults to "string," which is why the .map function throws an error.

If you expect an array of items as the output, make sure to define the TResult type parameter like @cherryblossom mentioned:

t<itemProps[]>('websites', {returnObjects: true}).map(...)

It's always helpful to refer to the type definitions of the libraries you are utilizing when dealing with issues like this. Make it a habit to consult them initially in such situations.

Answer №2

While I'm not an expert on i18, you might want to consider using the following code snippet:

t<itemProps[]>('websites', {returnObjects: true}).map(({slug, name}: itemProps) => ( ... ))

This code informs TypeScript that t will be returning an array of itemProps.


I was curious if simply removing underlines for .map would work.

It's generally not recommended to ignore TypeScript compiler errors. However, in exceptional cases, you can utilize // @ts-ignore above the line of code to suppress the error.

Answer №3

Since the latest version of i18next (version 23), a change has been made where you now need to provide 3 type arguments when using the t function. The first argument is for the key type, the second is for any options you want to pass, and the third is for the return type.

An example of how you would write this is:

t<'websites', { returnObjects: true }, itemProps[]>('websites', {returnObjects: true}).map(({slug, name}: itemProps) => ( ... ))

This new approach can be quite verbose, so you may consider creating your own reusable function to streamline this process and reduce boilerplate code.

For more information, visit: https://github.com/i18next/i18next/issues/2151

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Offering a limited selection of generic type options in TypeScript

Is there a shorthand in TypeScript for specifying only some optional types for generic types? For example, let's say I have a class with optional types: class GenericClass<A extends Type1 = Type1, B extends Type2 = Type2, C extends Type3 = Type3> ...

Encountering the 404 Page Not Found error upon refreshing the page while utilizing parallel routes

I'm currently developing a webapp dashboard using the latest version of Next.js 13 with app router. It features a dashboard and search bar at the top. I attempted to implement parallel routes. The @search folder contains the search bar and page.jsx wh ...

Continuously apply the template in a recursive manner in Angular 2 without reintroducing any duplicated components

Recently, I delved into the world of angular 2 and found it to be quite fascinating. However, I'm currently facing a roadblock and could really use some assistance. The scenario is as follows: I am working on creating a select box with checkboxes in ...

Create your own Angular control - rate stars - with dynamic input values

<div class="rating"> <div style="display: inline-block" *ngFor="let starred of stars; let i = index" (click)="rate(i + (starred ? (value > i + 1 ? 1 : 0) : 1))"> <ng-container *ngIf="starred; else noStar"><mat-icon class=" ...

Guide to successfully submitting an Angular form that includes a nested component

I have developed a custom dateTime component for my application. I am currently facing an issue where I need to integrate this component within a formGroup in a separate component. Despite several attempts, I am unable to display the data from the child fo ...

Angular is used to call a function that captures a specific div and then waits for the capture to be completed before

I'm facing a challenge where I need to handle the capturing of a div using a method called capture() within another method. Take a look at the code snippet below: theimage; // declaring the variable callcapture() { // perform certain actions t ...

What role does the @Input statement in the HeroDetailComponent class serve in the Angular 2 Quickstart tutorial?

Looking at the multiple components part of the Angular 2 Quickstart tutorial, we see how a component is separated from the AppComponent to enhance reusability and testing convenience. You can try out the example live demo here. In this scenario, users ar ...

Managing enum types with json2typescript

After receiving a JSON response from the back-end that includes an Enum type, I need to deserialize it. The JSON looks like this: { ..., pst:['SMS','EMAIL'], ... } In Typescript, I have defined my enum class as follows: export enum Pos ...

Is there a way to track all Angular form controls that have switched between being enabled and disabled?

Summary: When a FormGroup contains a nested FormControl that changes from disabled to enabled or vice versa, the FormGroup is not marked as dirty. Details: How can you identify all form controls within a FormGroup that have switched between being enabled ...

What method can be used to inherit the variable type of a class through its constructor

Currently, I am in the process of creating a validator class. Here's what it looks like: class Validator { private path: string; private data: unknown; constructor(path: string, data: string) { this.data = data; this.path = path; } ...

How come ngOnChange is unable to detect changes in @Input elements when ngOnDetect is able to do so?

Check out this plunker Please note: In order to see the effect, you need to restart the app after entering the link. import {Component, OnInit, Input, OnChanges, DoCheck} from 'angular2/core' @Component({ selector: 'sub', templat ...

Tips on changing the image source when hovering over it

Currently, I am exploring the usage of Next.js Image component to display images on my application page. However, I am encountering challenges in grasping how to choose and update the main Image src in order to replace it with all the responsive sizes that ...

How can a nullable variable be converted into an interface in TypeScript?

Encountered an issue while working on a vue3.x typescript project. The vue file structure is as follows: <template> <Comp ref="compRef" /> </template> <script lang="ts" setup> import {ref} from "vue& ...

"Jest test.each is throwing errors due to improper data types

Currently, I am utilizing Jest#test.each to execute some unit tests. Below is the code snippet: const invalidTestCases = [ [null, TypeError], [undefined, TypeError], [false, TypeError], [true, TypeError], ]; describe('normalizeNames', ...

Selecting the optimal data structure: weighing the benefits of using boolean check versus array .include (balancing performance and redundancy

My objects can have one or more properties assigned, with a total of 5 different properties in my case. To illustrate this, let's use a simple movie example where each movie can be assigned from 5 different genres. I have come up with two methods to ...

What causes the discrepancy in button appearance between Next.js 14, next/font, and Tailwind CSS?

I am currently facing a challenge in upgrading to nextjs 14 due to my struggle with incorporating next/font. I have two buttons with identical tailwind classes, except for the last className that pertains to nextjs font. Below is the code snippet: import ...

Making retries with the RetryWhen filter in Angular 2 RxJS Observables when encountering errors in the status

I'm currently working with the Angular 2 HTTP library, which returns an observable. I'm trying to set up a retry mechanism for specific error statuses/codes. The problem I'm facing is that when the error status is not 429, Observable.of(err ...

Conceal object from inventory upon clicking

As someone who is new to React and Typescript, I am facing challenges in understanding how to hide a ticket from the list when the hide button is clicked. displayTickets = (tickets: Ticket[]) => { const filteredTickets = tickets.filter(t => ...

Exporting components as the default from Next.js leads to a forced page refresh whenever there is a change

One issue I encountered involved having an index.tsx file containing all the shared UI components. When I exported the Footer and imported it into my shared Layout.tsx, which is utilized across all pages, the browser would refresh the page every time a cha ...

What is the process for incorporating a standalone custom directive into a non-standalone component in Angular?

Implementing a custom directive in a non-standalone component I have developed a custom structural directive and I would like to use it across multiple components. Everything functions as expected when it is not standalone, but encountering an error when ...