Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How To Declare TypeScript Static Method From React Functional Component

I'm needing to reference static methods from my functional component in React. I've made a small example here of what I want to do (it works in JavaScript). The error I'm getting is on line 10 const x = ...

TS2339: Property 'GetMyArray' does not exist on type 'FunctionComponent'.

import React, {FunctionComponent} from 'react';

interface Props {
    isLoading?: boolean,
}

const Speakers : FunctionComponent<Props> = ({isLoading}) => {

    if (isLoading) {
        const x = Speakers.GetMyArray();
        return (
            <div>{JSON.stringify({x})}</div>
        );
    } else {
        return <div></div>;
    }
};

Speakers.GetMyArray = () => {
    return [1,2,3,4]
};

export default Speakers
like image 281
Peter Kellner Avatar asked Dec 21 '18 19:12

Peter Kellner


3 Answers

This would be easier to do by using a class component since the static functions and property types can be inferred in class definitions.

class Speakers extends React.Component<Props> {
  static GetMyArray = () => [1, 2, 3, 4]

  render() {
    const { isLoading } = this.props
    if (isLoading) {
      const x = Speakers.GetMyArray(); // works great
      return (
        <div>{JSON.stringify({x})}</div>
      );
    } else {
      return <div></div>;
    }
  }
}

That said, you could do it extending React.SFC or using an intersection type:

const Speakers: React.SFC<Props> & { GetMyArray?: () => number[]; } = (props) => {
  const { isLoading } = props
  if (isLoading) {
    const x = Speakers.GetMyArray!(); // works, sorta
    return (
      <div>{JSON.stringify({x})}</div>
    );
  } else {
    return <div></div>;
  }
}

You'll have to mark GetMyArray as optional because you cannot define it at the same time as you define the function, so you'll have to use a ! operator (or check that the function exists) when calling the static function. The ! in Speakers.GetMyArray!(); tells the type checker that you know what you're doing and that GetMyArray is not indeed undefined. See here to read about the non-null assertion operator

Update

I did not see that using React.FC is now the preferred way to use function components since function components can no longer be considered stateless.

If you can get away with only using const Speakers = (props: Props) => ... then upgrading TypeScript to 3.1 might be your best bet!

like image 199
Stuart Bourhill Avatar answered Oct 18 '22 11:10

Stuart Bourhill


My answer is not exact to your question. But I think will be helpful for someone who wants to add a static component to the function component.

import React from 'react';
import { Text } from 'react-native';
import Group, { RadioButtonGroupProps } from './Group';

type RadioButtonType = {
  text: string,
};

interface StaticComponents {
  Group?: React.FC<RadioButtonGroupProps>
}

const RadioButton: React.FC<RadioButtonType> & StaticComponents = 
({ text }) => (<Text>{text}</Text>);

RadioButton.Group = Group;

export default RadioButton;

Remember config like this if you want to import React from 'react' directly instead of import * React from 'react'

Achievement:

enter image description here

like image 36
Long Nguyen Avatar answered Oct 18 '22 11:10

Long Nguyen


You can write an interface that extends React.FC with your custom static method, then assign that interface to your functional component.

// Extends FC with custom static methods
interface ComponentWithStaticMethod<TProps> extends React.FC<TProps> {
  staticMethod: (value: string) => void;
}

// Your component with the interface
const Component: ComponentWithStaticMethod<{}> = () => {
  // Your component goes here...
  return null;
}

// Declare your static method for your functional component
Component.staticMethod = (value: string): void => {
  console.log(value);
}
like image 30
junwen-k Avatar answered Oct 18 '22 10:10

junwen-k