Dynalon
Dynalon

Reputation: 6814

TypeScript conditional types: Extract component props type from react component

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?

Upvotes: 46

Views: 32213

Answers (3)

Sebastien Lorber
Sebastien Lorber

Reputation: 92210

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

Upvotes: 134

SleepWalker
SleepWalker

Reputation: 1281

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;

Upvotes: 11

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 250366

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

Upvotes: 5

Related Questions