Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to type the style property for components to accept arrays?

In React Native, view elements accept a style property that uses CSS property names in a camel cased object:

const styleObj = {
  width: 200,
  marginTop: 10
}

Elements also accept an array of style objects like this:

<MyComponent style={[ styleObj, styleProp && styleProp ]} />

I have several abstracted button components that rely on a shared base button interface. For simplicities sake:

interface IButton {
  style?: ViewStyle | ViewStyle[] // <-- ViewStyle is exported by react native, and contains all the allowed style properties for a View component
}

I thought this definition would be adequate, but I'm running into some issues that I'm having difficulty understanding.

I have a DropDown component which renders a Button. When I use the style prop I get an error:

<Button
  style={[
    {
      backgroundColor: backgroundColor || COLORS.lightRed,
      borderRadius: 3,
      height: 44,
      width: '100%',
     },
     style && style, // <-- type is ViewStyle | ViewStyle[], this is passed in as a prop
  ]}

The above throws the error:

Type (ViewStyle | ViewStyle[] | undefined)[] is not assignable to ViewStyle | ViewStyle[] | undefined

If I cast style: style && (style as ViewStyle) I get a different error:

Type (ViewStyle | undefined)[] is not assignable to ViewStyle[]

If I cast the entire array is a ViewStyle the error clears:

<Button
  style={[
    {
      backgroundColor: backgroundColor || COLORS.lightRed,
      borderRadius: 3,
      height: 44,
      width: '100%',
     },
     style && style,
  ] as ViewStyle}

Which is fine but I'm a bit confused. I have a hunch that, since my components are using the same props interface, TypeScript is getting confused. Ultimately I'm unsure why those errors are happening, and what is incorrect about my definition that I need to rely on casting.

like image 256
Robbie Milejczak Avatar asked Feb 11 '19 16:02

Robbie Milejczak


1 Answers

As obvious as this should have been, it took me a while to find the best solution.

When typing your style props, use ViewStyle, TextStyle etc (instead of StyleProp<T>), and when passing an array of styles simply use Stylesheet.flatten() to silence any type incompatibilities:

<Button
  style={Stylesheet.flatten([
    {
      backgroundColor: backgroundColor || COLORS.lightRed,
      borderRadius: 3,
      height: 44,
      width: '100%',
     },
     style && style,
  ])}
like image 114
Robbie Milejczak Avatar answered Oct 10 '22 14:10

Robbie Milejczak