10

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
2

5 Answers 5

6

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!

Sign up to request clarification or add additional context in comments.

1 Comment

I am kind of disagreeing with Passing the function as optional. This can create Problems. I would argue why, include it as part of the Component itself.(The Fn I mean). He only needs to call it either way. Also, the Union you are creating there, can be a little problematic. Can you explain your thoughts a little. Maybe I am missing something here.
5

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

Comments

1

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);
}

Comments

0

You should have it working since TS version 3.1 (see section "Properties declarations on functions")

3 Comments

I’m using react hooks so have to use functional components. I’m brand new to typescript.
@PeterKellner I talk about typescript version (React is irrelevant to this problem, you can see the error code is TS2339 which is typescript's), which should be at least 3.1. Can you check it in CLI tsc -v. If it is not installed globally, then you can see it in your package.json
I'm using 3.2.2
0

Main Answer

For future googlers out there, now it works as intended:

interface Props {
  isLoading?: boolean,
}

interface StaticFields {
  staticField: number,
  staticFunctionField: () => void,
}

export const Component: FC<Props> & StaticFields = (props) => {}

Component.staticField = 42;
Component.staticFunctionField = () => {}

Special Case: memo and forwardRef

In such cases, you won't be able to define typings like in above. Using Object.assign can solve the problem:

import { memo } from 'react'

interface Props {
  isLoading?: boolean,
}

const Component = memo((props: Props) => {})

export const ComponentWithStaticFields = Object.assign({}, Component, {
  staticField: 42,
  staticFunctionField: () => {},
})

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.