48

Using TypeScript 2.8 new conditional generic type feature, is it possible to extract the TProps of a React.ComponentType<TProps> component? I want a type that can either work on the ComponentType or the TProps itself, so you can - as a developer - pass either of both:

For example:

interface TestProps {
    foo: string;
}

const TestComponent extends React.Component<TestProps, {}> {
    render() { return null; }
}

// now I need to create a type using conditional types so that
// I can pass either the component or the props and always get the 
// TProps type back
type ExtractProps<TComponentOrTProps> = /* ?? how to do it? */

type a = ExtractProps<TestComponent> // type a should be TestProps
type b = ExtractProps<TestProps>     // type b should also be TestProps

Is this possible, and can anybody provide a solution?

1

3 Answers 3

136

There's a built-in helper for that

type AnyCompProps = React.ComponentProps<typeof AnyComp>

And it also works for native DOM elements:

type DivProps = React.ComponentProps<"div">

https://stackoverflow.com/a/55005902/82609

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

2 Comments

Nice find Sebastien.
This is the way.
11

I'd suggest to use React.ComponentType, because it will also include functional components:

type ExtractProps<TComponentOrTProps> =
  TComponentOrTProps extends React.ComponentType<infer TProps>
    ? TProps
    : TComponentOrTProps;

2 Comments

Marking your answer as the right one now, as I also support functional/hooks based component introduced in React 16.8.
Why returning TComponentOrTProps if it doesn't extend from React.ComponentType ?
5

It's a pretty straight forward application of conditional types and their inference behavior (using the infer keyword)

interface TestProps {
    foo: string;
}

class TestComponent extends React.Component<TestProps, {}> {
    render() { return null; }
}

type ExtractProps<TComponentOrTProps> = TComponentOrTProps extends React.Component<infer TProps, any> ? TProps : TComponentOrTProps;

type a = ExtractProps<TestComponent> // type a is TestProps
type b = ExtractProps<TestProps>     // type b is TestProps

3 Comments

This does not work anymore with React functional components introduced in React 16.8 (type React.FC<TProps>)
Why returning TComponentOrTProps if it doesn't extend from React.ComponentType ?
@CristianE. I think that this is needed to make ExtractProps<TestProps> work. If ExtractProps used with React.Component, it will extract props from it's declaration. Otherwise ExtractProps will assume that TComponentOrTProps is simply a Props interface and will return it as is

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.