Search code examples
reactjsreact-nativeflowtypeflow-typed

Extending flow `type Props` to include prop types from another component?


I have following component that mainly relies on Image from react-native

// @flow
import React from "react";
import { Image } from "react-native";
import { deviceWidth } from "../services/device";

type Props = {
  width: number,
  ratio: number
};

class RatioImage extends React.Component<Props> {
  render() {
    const { width, ratio, style, ...props } = this.props;
    return (
      <Image
        {...props}
        style={[
          {
            width: deviceWidth * (width / 100),
            height: deviceWidth * (width / 100) * ratio
          },
          style
        ]}
      />
    );
  }
}

export default RatioImage;

I was able to type annotate my own props, but in example above style throws an error

[flow] property style (Property not found in Props) const style: any

I know that in typescript I can just extend interface to Image one, is there something in flow that I can use in order to make my props inherit all types from Image somehow? How would I even import such types from react-native?

EDIT I found out about concept called intersection types and tried this

import { Image, type Image as ImageProps } from "react-native";
type Props = ImageProps & {
  width: number,
  ratio: number
};

but style is still throwing an error, although different one

[flow] property style (Property cannot be accessed on any member of intersection type intersection Member 1: ImageProps Error: property style Property not found in React component Member 2: object type Error: property style Property not found in object type) const style: any


Solution

  • Unfortunately, React Native is not 100% consistent in the way it uses flowtypes.

    If you were trying to do the same for the Text component, you could simply import the type definition from the internal TextProps module provided by the global Haste namespace, and create your own supertype using Flow type unions:

    import type { TextProps } from 'TextProps';
    
    type ExtendedTextProps = TextProps & {
      additionalProp: string
    };
    

    That said, there is no ImageProps module for you to import. If you look at the Image (iOS) component types, they're still expressed as PropTypes.

    At this time, I believe, the easiest way for you to add full type coverage for your custom image component would be look at the Image component's PropTypes and convert them to Flow types by hand. Some of the more complex field types such as ImageSource and ImageStyle already exist as flowtypes.

    I'm not sure what the core team's intention is going forward, but it might be worth considering contributing the type defs to React Native itself and solving this problem for future users.