Index TypeScript

color is a string that defaults to primary
but when passed into the Colors array as an index I’m promptly informed that it’s an any type because a string can’t be used as an index on type ‘{…etc}’


Colors are just the default constants with the tab template out of Expo, but I’m extending the color palette.

I’m still fairly new to typescript, but I don’t think there is an index type…
So my question is what should I be setting its type to?

import React from 'react'
import {
  StyleSheet,
  Text,
  TouchableOpacity,
  View,
} from 'react-native'

import Colors from '../constants/Colors';

interface AppButtonProps {
  color?: string[];
  title?: string;
  onPress?: any;
}

const AppButton: React.FC<AppButtonProps> = ({
  color = 'primary',
  title = 'default App Button',
  onPress = () => console.log('default AppButton'),
}) => {
  return (
    <View style={styles.container}>
      <TouchableOpacity
        style={[styles.button, { backgroundColor: Colors[color] }]}
        onPress={onPress}
      >
        <Text style={styles.text}>{title}</Text>
      </TouchableOpacity>
    </View>
  )
}

const styles = StyleSheet.create({
  container: {
    // backgroundColor: 'yellow',
  },
  button: {
    backgroundColor: Colors.primary,
    borderRadius: 25,
    justifyContent: "center",
    alignItems: "center",
    padding: 15,
    width: "100%",
    marginVertical: 10,
  },
  text: {
    color: Colors.white,
    fontSize: 18,
    textTransform: "uppercase",
    fontWeight: "bold",
  },
})

export default AppButton
1 Like

Is… that an object? If so, why are we using ='s instead of :'s?

if I change it to the colon’s the IDE doesn’t like it… I think the difference is the parathesis around it passing it up to be called in a functional component.
Screenshot from 2021-06-05 07-02-45

oh, okay… it’s… a function definition, that expects an object, that has default values… I get it now… syntax makes my head hurt, but… sure… i guess? I’m not sure how it translates the object into a set of variables available to the output function, maybe thats a TypeScript thing.

I assume that you’re seeing a valid value for title where it should be?

yes, the default values seem to come through, even the color is functional, I’m just new to TypeScript and trying to trace down all the red squiggles, and thought that this would be an easier one. I mean the button is still drawing the default text and color and I can pass new settings for each, so it’s functional. But it’s also a base component. I thought getting all the typescript warnings now would save me headaches using it in larger components later.
I notice the Color object will only take light or dark for the theming, so I’m wondering if I should come on the Expo forum and try to track down where they are setting the type for the constant Color. It seems to be a Global they are using for theming. I may just need to duplicate such an interface for the palette as a separate object
https://stackoverflow.com/questions/67847573/what-type-should-i-assign-to-an-index

Hi @TurtleWolf1, you might either explicitly specify a union type allowing only valid keys, such as:

interface AppButtonProps {
  color: 'primary' | 'secondary';
  // ...
}

Or, you might allow any key of your Colors object like so:

interface AppButtonProps {
  color: keyof typeof Colors;
  // ...
}

Yet another option would be to define an actual interface for the Colors object… if this is based on / using a 3rd oarty library, such an interface might already exist.

2 Likes

this sounds like what I was looking for, I’ll let you know after testing, thank you

1 Like

the layered nesting still seemed to be an issue…
so I went ahead and separated palette as it’s on object.
but it seems to be working perfectly. I should probably start a new thread for this but any advice on how to pass a function, (any) is what I’m getting so far?

interface AppButtonProps {
  // color?: 'primary' | 'secondary' | 'danger' | 'black' | 'darkGrey';
  color?: keyof typeof palette;
  title?: string;
  // onPress?: any;
  onPress?: (any);
  // children?: Element | React.ReactNode;
  // AppButton?: string;
}

You mean the function signature? This can be done like e.g.

interface AppButtonProps {
  onPress?: (event: TouchEvent) => void;
}

… where event is the parameter name, TouchEvent the parameter type, and void the return type (it doesn’t return anything in this case).