Retrieve the value of a variable to access an object property dynamically in React Native using TypeScript

As I attempted to create dynamic styles for this component, my goal was to determine the styles based on a string passed in as a property. Here is the code snippet:

export type MyComponentProps = {
  styleName: string;
}

const MyComponent = (props: MyComponentProps) => {
  const { styleName } = props;
  
  return (
    <View
      style={[
        styles['container'],
        styles[`view${styleName}`],
      ]}>
      <Text
        style={[
          styles['text'],
          styles[`text${styleName}`],
        ]}>
        Hello World
      </Text>
    </View>
  );
}


const styles = StyleSheet.create({
  container: {
    width: '100%',
    alignItems: 'center',
  },

  viewDark: {
    backgroundColor: 'black',
  },

  viewLight: {
    backgroundColor: 'white',
  },

  text: {
    fontWeight: 'bold',
  },

  textDark: {
    color: 'white',
  },

  textLight: {
    color: 'black',
  },
}

However, I encountered an error stating:

'Element implicitly has an 'any' type because expression of type '`view${any}`' can't be used to index type '{ container: { width: string; alignItems: "center"; }; viewDark: { backgroundColor: string; }; viewLight: { backgroundColor: string; }; text: { ...; }; textDark: { ...; }; textLight: { ...; }; }'.

I wanted to avoid passing any styles directly through the props, as it's not commonly recommended.

Although unconventional, I intentionally used styles['container'] instead of styles.container, to highlight the distinction between the two cases with ${styleName} being the only variable factor.

Answer №1

Through our investigation, it has become evident that we can achieve this task by converting the dynamically generated string to a keyof the interface assigned to the styles variable. The following example demonstrates how:

export type MyComponentProps = {
  styleName: string;
}

const MyComponent = (props: MyComponentProps) => {
  const { styleName } = props;
  
  return (
    <View
      style={[
        styles['container'],
        styles[`view${styleName}` as keyof IStyles],
      ]}>
      <Text
        style={[
          styles['text'],
          styles[`text${styleName}` as keyof IStyles],
        ]}>
        Hello World
      </Text>
    </View>
  );
}

interface IStyles {
  container: object,
  viewDark: object,
  viewLight: object,
  text: object,
  textDark: object,
  textLight: object,
}

const styles: IStyles = StyleSheet.create({
  container: {
    width: '100%',
    alignItems: 'center',
  },

  viewDark: {
    backgroundColor: 'black',
  },

  viewLight: {
    borderColor: 'white',
  },

  text: {
    fontWeight: 'bold',
  },

  textDark: {
    color: 'white',
  },

  textLight: {
    color: 'black',
  },
}

Remember to define styles with the interface IStyles using const styles: IStyles = ...

Answer №2

There may be instances where the alternative solution doesn't seem to work, but I'll still include it for readers' reference. This method has proven to be reliable thus far without requiring the creation of an interface, which could be seen as a benefit.

export type MyComponentProps = {
  styleName: string;
}

const MyComponent = (props: MyComponentProps) => {
  const { styleName } = props;

  const viewStyle = `view${styleName}`; // Possibly easier to understand
  
  return (
    <View
      style={[
        styles['container'],
        `view${styleName}` == 'viewDark'
          ? styles['viewDark']
          : {},
        viewStyle == 'viewLight' // Using the more understandable option
          ? styles['viewLight']
          : {},
      ]}>
      <Text
        style={[
          styles['text'],
          `text${styleName}` == 'textDark'
          ? styles['textDark']
          : {},
          `text${styleName}` == 'textLight'
          ? styles['textLight']
          : {},
        ]}>
        Hello World
      </Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    width: '100%',
    alignItems: 'center',
  },

  viewDark: {
    backgroundColor: 'black',
  },

  viewLight: {
    borderColor: 'white',
  },

  text: {
    fontWeight: 'bold',
  },

  textDark: {
    color: 'white',
  },

  textLight: {
    color: 'black',
  },
}

One drawback is that we need to manually write if statements to check each possible style individually, but the benefit is that it seems to be more dependable in practice.

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

What is the process for defining a recursive array data structure?

Looking to implement a TypeScript method that can navigate through nested arrays of strings when given an instance of a type/class/interface. The method, in concept, should resemble: method<T>(instance: T, arrayAttr: someType) { let tmp = undefin ...

Unable to sign out user from the server side using Next.js and Supabase

Is there a way to log out a user on the server side using Supabase as the authentication provider? I initially thought that simply calling this function would work: export const getServerSideProps: GetServerSideProps = withPageAuth({ redirectTo: &apos ...

Contrary to GraphQLNonNull

I am currently working on implementing GraphQL and I have encountered a problem. Here is an example of the code I wrote for GraphQL: export const menuItemDataType = new GraphQL.GraphQLObjectType({ name: 'MenuItemData', fields: () => ...

Resolving circular dependencies caused by APP_INITIALIZER

My AuthenticationService is responsible for loading the AngularFirestore and is loaded in the RootComponent. All app modules are lazily loaded within the RootComponent (which contains the main router-outlet). However, several sub-modules also load the Ang ...

How can different styles be seamlessly combined when customizing Fabric components?

Imagine I am enhancing a Fabric component by adding custom styles and wishing to combine any additional styles passed in through its props. Here's the solution I've devised: const { TextField, Fabric , IButtonProps, mergeStyleSets } = window.Fab ...

Strange problem encountered when transferring data to and from API using Typescript and Prisma

I'm encountering a strange issue that I can't quite pinpoint. It could be related to mysql, prisma, typescript, or nextjs. I created the following model to display all product categories and add them to the database. Prisma Model: model Product ...

Having trouble retrieving state data within a functional component in React Native

I've been facing a challenge while developing an app in React Native. The issue lies in understanding how to manage state in functional components. After successfully fetching and storing an array of activities in the component's state, I encoun ...

Using React with Typescript: Anticipating child component with particular props

I'm currently developing a component that necessitates the use of two specific child components. These two components are exported using dot notations from the main component and have defaultProps for identification within the main component: export ...

What is the best way to execute a sequence of http requests only after the previous one has been completed successfully, while also addressing any

Working with Angular/rxjs 6 has brought me to a challenge. I'm struggling to get an observable sequence to run smoothly as intended. Here's the concept of what I'm trying to achieve: Request received to change systems: Check permissions Fe ...

What are some best practices for integrating ES2020 into an Angular project?

Below is the content of my tsconfig.json file: { "compileOnSave": false, "compilerOptions": { "baseUrl": "./", "outDir": "./dist/out-tsc", "sourceMap&q ...

Asynchronous retrieval of reference value from Firebase Firestore in ReactJS

Encountering a peculiar bug in TypeScript-JavaScript where I have a Model class in TypeScript and a ReactJS Component in JS. The issue arises when dealing with a list of Promo Objects, each containing a "_listCompte" property which holds a list of Compte O ...

Unable to access current props within useEffect block

When I use useEffect with the parameter props.quizStep, my function fn (which is a keydown event listener) is unable to access the current value of props.quizStep. I'm puzzled as to why it's not working properly. Can you help me understand? Bel ...

Prisma: Utilizing the include option will retrieve exclusively the subobject fields

I created a function to filter the table building and optionally pass a Prisma.BuildingInclude object to return subobjects. async describeEntity(filter: Filter, include?: Prisma.BuildingInclude): Promise<CCResponse> { try { const entity = await ...

Switching between various components based on conditions within the same route in Angular

My goal is to have 2 separate views, one for the homepage and another for authentication. I want to display the LoginComponent on the route '/' and the SignupComponent on the route '/signup' if the user is not logged in, otherwise rende ...

React Component Fails to Refresh After Redux Modifications

I've recently started learning about React and Redux, and I've been trying to solve a particular issue for the past few days. The problem I'm facing is that my React component doesn't re-render when Redux updates. Despite seeing the st ...

Angular2 data binding does not update when properties change

I'm struggling to establish the connection between the fields and the component in order for them to update when the properties change in OnDataUpdate(). The field "OtherValue" successfully binds two ways with the input field, and the "Name" field di ...

Methods for adding a new object to an array in Angular: Explained

How can I insert a new object in Angular? Here is the current data: data = [ { title: 'Book1' }, { title: 'Book2' }, { title: 'Book3' }, { title: 'Book4' } ] I would like to update the obje ...

TS7030: In Angular13, ensure that all code paths within the guard and canActivate methods return a value

Having trouble using guards for an unlogged user and constantly facing errors. Error: TS7030 - Not all code paths return a value. Below is my auth.guard.ts file: import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree} from &a ...

Sending the `onChange` prop from a parent component to a group of child elements

If I have a setup with a component like the example below, how can I efficiently pass the onChange prop to every instance of DropdownItem? Rather than adding it directly to each DropdownItem, which could become repetitive. <Dropdown onChange={(select ...

Angular Form customizable field

I'm trying to figure out how to create an angular form with a dynamic step. Currently, my form in TypeScript looks like this: this.registerForm = new FormGroup({ role: new FormControl('', [ Validators.required, ]), firstName: ...