Manipulate the name of a property or field using TypeScript

I am in the process of creating a bilingual blog using Nuxt.js and TypeScript. This application interacts with a REST API to retrieve data that is structured like this:

{
  "Headline_de": "Mein erster Blogpost",
  "Headline_en": "My first Blogpost"
}

Retrieving data for one language from the API looks like this:

export const mutations = {
  setCurrentBlogpost(state, blogpostId) {
    const currentBlogpost = await axios.get(api + blogpostId);
    
    const normalizedBlogpost = {
      headline: currentBlogpost.Headline_de
    };
    state.commit('setCurrentBlogpost', currentBlogpost.data);
  }
};

Now I want to fetch the data based on the currently selected language. I attempted to manipulate the property like so:

const headline = 'currentBlogpost.Headline_' + this.$i18n.locale; // outputs de or en

export const mutations = {
  setCurrentBlogpost(state, currentBlogpost) {
    const normalizedBlogpost = {
      headline: headline
    };
    state.currentBlogpost = normalizedBlogpost;
  }
};

However, this approach only sets the property as a string. Is there a method to manipulate the input properties to address this issue?

Edit: I managed to make it work using this method. But I believe there might be a simpler solution.

setCurrentBlogpost(state, currentBlogpost) {

    if (this.$i18n.locale == 'de') {
      const normalizedBlogpost: Blogpost = {
        headline: currentBlogpost.Headline_de
      };
      state.currentBlogpost = normalizedBlogpost;
    }

    if (this.$i18n.locale == 'en') {
      const normalizedBlogpost: Blogpost = {
        headline: currentBlogpost.Headline_en
      };
      state.currentBlogpost = normalizedBlogpost;
    }
  }

Answer №1

To access the correct value from currentBlogpost, you should use bracket notation such as currentBlogpost[headline]. Here, headline can be either "Headline_en" or "Headline_de".

In TypeScript 4.1 and above, by utilizing a template literal to define the headline string, one can employ a template literal const assertion to enforce a template literal type. Specifically, using the template literal

`Headline_${this.$i18n.locale}` as const
will result in the type
"Headline_en" | "Headline_de"
:

$i18n = {
  locale: Math.random() < 0.5 ? "de" as const : "en" as const
}

method() {
  const currentBlogpost = {
    "Headline_de": "Mein erster Blogpost",
    "Headline_en": "My first Blogpost",
  }
  const headline = `Headline_${this.$i18n.locale}` as const;
  const normalizedBlogpost = {
    headline: currentBlogpost[headline], // <-- this type checks!
  };
}

Prior to TS4.1, the compiler would only recognize headline as type string, which is too broad to function as a property key of currentBlogpost without an explicit type assertion:

const headline = "Headline_"+this.$i18n.locale; // string
const normalizedBlogpost = {
  headline: currentBlogpost[headline], // error!  No index signature 
};

Explore code on Playground

Answer №2

Special thanks to @Zdeněk Jelínek for providing valuable insights that helped me create a more efficient solution. Here is the updated implementation that has been working smoothly:

  setNewBlogpostState(state, newBlogpost) {
    const language = this.$i18n.language;

    const modifiedBlogpost: Blogpost = {
      title: newBlogpost['Title_' + language],
    };
    state.newBlogpost = modifiedBlogpost;
  }
};

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

Navigating horizontally to find a particular element

I developed a unique Angular component resembling a tree structure. The design includes multiple branches and nodes in alternating colors, with the selected node marked by a blue dot. https://i.stack.imgur.com/fChWu.png Key features to note: The tree&ap ...

The test() function in JavaScript alters the output value

I created a simple form validation, and I encountered an issue where the test() method returns true when called initially and false upon subsequent calls without changing the input value. This pattern repeats with alternating true and false results. The H ...

Issues with type errors in authentication wrapper for getServerSideProps

While working on implementing an auth wrapper for getServerSideProps in Next.js, I encountered some type errors within the hook and on the pages that require it. Below is the code for the wrapper along with the TypeScript error messages. It's importan ...

Unexpected behavior encountered with RxJs Subject.subscribe function

When calling the Subject.subscribe method, an error is output as follows: TypeError: Cannot read property '_subscribe' of undefined at BidirectionalSubject._subscribe (Rx.js:10239) at BidirectionalSubject._subscribe (Rx.js:10239) at Bidirection ...

When using Webpack and Typescript together with the watch feature, an error with code TS2554 may occur only during

Software in use: webpack 4.8.3 typescript 2.8.3 ts-loader 4.3.0 Configuration for Webpack: rules: [ { test: /\.ts(x?)$/, exclude: /node_modules/, use: ['ng-annotate-loader', 'ts-loader'] }, . ...

What is causing the undefined value for the http used in this function?

My Code Component import { Component, OnInit } from '@angular/core'; import { Http } from '@angular/http'; @Component({ selector: 'app-root', template: '<button id="testBtn"></button>' }) export c ...

RXJS: Introducing a functionality in Observable for deferred execution of a function upon subscription

Implementing a Custom Function in Observable for Subscribers (defer) I have created an Observable using event streams, specifically Bluetooth notifications. My goal is to execute a function (startNotifictions) only when the Observable has a subscriber. ...

Discover the data type without using the extends keyword within an interface in Typescript

I'm struggling with making my code declarative enough. I want to infer a type inside an interface scope and then use that same type as an argument for a method within the interface. Here is a simple example: interface Prop { x: infer U, // ^^ ...

Having an excess of 32 individual byte values

My current project involves developing a permission system using bitwise operators. A question came up regarding the limitation of having only 32 permissions in place: enum permissions { none = 0, Founder = 1 << 0, SeeAdmins = 1 << ...

Guide to integrating Mongoose typings with Angular 2 webpack starter

As a newcomer, I'm hoping this issue is straight forward. I am currently utilizing the angular2-webpack-starter found on GitHub. Based on the mongoose documentation, it appears that including their JavaScript file allows for accessing a global varia ...

When declaring an array of numbers in sequelize-typescript, it triggers a TypeScript error

In my application, I am working with PostgreSQL, Sequelize, Sequelize-TypeScript, and TypeScript. I have a need for a table called Role where each role has multiple permissions of type integer. I'm following the guidelines provided in the sequelize-ty ...

A more efficient method for refreshing Discord Message Embeds using a MessageComponentInteraction collector to streamline updates

Currently, I am working on developing a horse race command for my discord bot using TypeScript. The code is functioning properly; however, there is an issue with updating an embed that displays the race and the participants. To ensure the update works co ...

Guide on setting default key/value state in TypeScript React application

Having the task of converting a React app to Typescript, I'm struggling to properly set the initial state of a hash object. Here is the original javascript code: export default class Wizard extends PureComponent { constructor(props) { su ...

Sign up for the identical Observable within a Child Component in Angular 2 using TypeScript

This question may seem simple, but as a newcomer to Angular 2, I often find myself needing more explanation despite the good examples and tutorials available. Within a component, I have an observable that gets updated periodically. While I've simplif ...

The argument '$0' provided for the pipe 'CurrencyPipe' is not valid

When retrieving data from the backend, I receive $0, but I need to display it as $0.00 in my user interface. <span [innerHTML]="session.balance | currency :'USD': true:'1.2-2'"></span> I'm encountering an issue where ...

Using the useState hook in a loop can sometimes result in a unique key error

Trying to add multiple items for rendering in my browser, but encountering an issue after clicking addItem. The item does render, however, I am getting the following error message: 'Warning: Each child in a list should have a unique ""key"" ...

What is the process for adjusting the color of axes in vue-chartjs?

Seeking help on how to adjust the color of the axis in my graph. Has anyone encountered a similar issue before? The chart I'm working with resembles the one shown in the image. Not sure if this issue is related to it being a time graph. Below is the V ...

A comprehensive guide on displaying data in Angular using an API

I have encountered an issue while trying to display data from an API in the 'home.component.html'. Although my 'home.component.ts' successfully fetches the data from the service, I'm facing difficulty rendering it in 'home.com ...

Angular 16 HttpClient post request with asynchronous action

Here I am working on integrating JWT in Angular with a .Net Core API. When I start my Angular server and launch the application, I encounter the following scenarios: Attempting with correct credentials initially fails, but retrying allows it to work. Tryi ...

Solution: How to fix the error: Invalid component type, 'Draggable' cannot be used with JSX in react-draggable

I encountered an error while working on this Next.js React project Type error: 'Draggable' cannot be used as a JSX component. Its instance type 'Draggable' is not a valid JSX element. The types returned by 'render()&apo ...