214

npm package @types/react allows us to use React inside of our TypeScript applications.

We define components as

type Props = {...}

type State = {...}

export default class MyComponent extends React.Component<Props, State> {
}

Here we have to declare types for component props and state (in type variables).

After we declared that types, TypeScript uses that to validate the usage of our component (the shape of props passed to it).

I want to create a container around such a component. The container will reuse the props of the component. But in order to create another component with the same props I have to redeclare the types for props again. Or export them from the original component file and import into container:

// Original file
export type Props = {...}

// Container file
import MyComponent, { Props } from './original'

But I'm already importing the MyComponent from that file. This component already contains information about the props it consumes (thanks to type variables in React.Component).

How do I access that information from the component class itself without explicitly exporting/importing the type for props?

I want something like:

import MyComponent from './MyComponent'

type Props = MyComponent.Props // <= Here access the component prop types

export default class MyContainer extends React.Component<Props, {}> {}
1
  • 1
    Hi. As of 2019 you should rather use this solution. Others will work but are not the most up to date and future-proof solutions: stackoverflow.com/a/55005902/82609 Commented Mar 5, 2019 at 15:11

5 Answers 5

572

2019: noticed all answers above are quite outdated so here is a fresh one.


Lookup type

With newer TS versions you can use lookup types.

type ViewProps = View['props']

Despite being very convenient, that will only work with class components.


React.ComponentProps

The React typedefs ship with an utility to extract the type of the props from any component.

type ViewProps = React.ComponentProps<typeof View>

type InputProps = React.ComponentProps<'input'>

This is a bit more verbose, but unlike the type lookup solution:

  • the developer intent is more clear
  • this will work with BOTH functional components and class components

All this makes this solution the most future-proof one: if you decide to migrate from classes to hooks, you won't need to refactor any client code.

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

10 Comments

And you can even get props of native elements like <input /> by passing string there React.ComponentProps<'input'>. Thanks :)
Unfortunately this doesn't work with Generic typed components like typeof View<ViewData>
Nice answer! However it doesn't take defaultProps into account. This one does: type MyCompProps = JSX.LibraryManagedAttributes<typeof MyComp, React.ComponentProps<typeof MyComp>>. See github.com/Microsoft/TypeScript/issues/…
how to write something like this at generic interface ... children: (props: React.ComponentProps<TComponent>) => TComponent;? where TComponent extends React.ReactNode
For built-in elements, you can also use: JSX.IntrinsicElements["div"] (though you may want to use Omit<..., "ref">, if you're using ...rest in your render function)
|
41

Starting with TypeScript 2.8, you can use conditional types, e.g. given:

interface MyComponentProps { bar: string; }
declare const MyComponent: React.Component<MyComponentProps>;

interface MyComponentClassProps { bar: string; }
declare const MyComponentClass: React.ComponentClass<MyComponentClassProps>;

interface MyStatelessComponentProps { bar: string; }
declare const MyStatelessComponent: React.StatelessComponent<MyStatelessComponentProps>;

We can define these helpers:

type GetComponentProps<T> = T extends React.ComponentType<infer P> | React.Component<infer P> ? P : never

And use them like so:

// $ExpectType MyComponentProps
type MyComponentPropsExtracted = GetComponentProps<typeof MyComponent>

// $ExpectType MyComponentClassProps
type MyComponentClassPropsExtracted = GetComponentProps<typeof MyComponentClass>

// $ExpectType MyStatelessComponentProps
type MyStatelessComponentPropsExtracted = GetComponentProps<typeof MyStatelessComponent>

Update 2018-12-31: this is now available in the official React typings via React.ComponentProps.

2 Comments

For the typescript newbies who might also be tripped up by what I missed: React.ComponentProps will only be defined inside of a type expression - so the right hand side of a type =, or anywhere that you would normally put an interface or type like typing the arguments of a function
If you're using this with a generic, the generic would have to look like this: T extends React.FC<any> | React.ComponentClass<any> and then you will be able to do this: type PropType = React.ComponentProps<T>;
7

To take a type of properties from component

type Props = typeof MyComponent.defaultProps;

You can ask yourself why I'm taking typeof from defaultProps and not from propTypes. To explain that lets take a look at the definition file

  interface ComponentClass<P> {
        new(props?: P, context?: any): Component<P, ComponentState>;
        propTypes?: ValidationMap<P>;
        contextTypes?: ValidationMap<any>;
        childContextTypes?: ValidationMap<any>;
        defaultProps?: P;
        displayName?: string;
    }

As you can see propTypes are wrapped in ValidationMap and it's not easy to get raw types. Fortunately, defaultProps have raw types

3 Comments

Cool! Thanks. Although this is not an explicit way of getting the type, it works for now (until the authors refactor the implementation).
Unfortunately this no longer works because defaultProps now has a type of Partial<P>.
@OliverJosephAsh that's true. If you really need that you can use module augmentation to extend react typings to put dummy type that would allow you to fetch prop types. Look here typescriptlang.org/docs/handbook/declaration-merging.html under Module Augmentation section
5

That's my solution of how to get props from component

type Propsable = {
  FC: React.FC;
  C: React.Component;
  CC: React.ComponentClass<any>;
  F: (...args: any) => any;
}
type PropsOfFC<C extends Propsable["FC"]> = {
  [K in keyof C["propTypes"]]: C["propTypes"][K] extends React.Validator<infer P>
    ? P
    : K
};
type PropsOfF<C extends Propsable["F"]> = Parameters<C>[0]
type PropsOfC<C extends Propsable["C"]> = C extends React.Component<infer P> ? P : never;
type PropsOfCC<C extends Propsable["CC"]> = C extends React.ComponentClass<infer P> ? P : never;


type PropsOf<C extends ValueOf<Propsable>> =
  C extends Propsable["FC"] ? PropsOfFC<C> :
  C extends Propsable["C"] ? PropsOfC<C> :
  C extends Propsable["CC"] ? PropsOfCC<C> :
  C extends Propsable["F"] ? PropsOfF<C> : any;

If you use functional component, class component or styled component that solution should help you.
How to use:

type Props = PropsOf<typeof YourComponent>

You can add this to 'react.d.ts'

1 Comment

Probably PropsOfFC could be Parameters<C>[0]
3

Given a React component:

import React, { ComponentType, StatelessComponent } from 'react';

const MyComponent: StatelessComponent<{ foo: string }> = props => <div>{props.foo}</div>;

You can do:

const getProps = function<Props> (_MyComponent: ComponentType<Props>): Props {
  return {} as Props;
};
const props = getProps(MyComponent);

// { foo: string; }
type MyComponentProps = typeof props;

Alternatively, you can augment the React typings to add a GetComponentProps helper:

import React from 'react';

type NonNullable < T > = T & {};

declare module 'react' {
  // Add helper for accessing props type of given component. Based off of
  // https://github.com/DefinitelyTyped/DefinitelyTyped/pull/24182.
  type GetComponentProps < C extends ComponentType < any > > = NonNullable<C['_doNotUse_props']>;

  // We use interface merging to append properties to these types
  interface StatelessComponent<P = {}> {
    // eslint-disable-next-line camelcase
    _doNotUse_props?: P;
  }
  interface ComponentClass<P = {}> {
    // eslint-disable-next-line camelcase
    _doNotUse_props?: P;
  }
}

Usage looks like this:

// { foo: string; }
type MyComponentProps = React.GetComponentProps<typeof MyComponent>;

I originally posted this in https://github.com/DefinitelyTyped/DefinitelyTyped/pull/24182.

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.