Typescript and React - Conditional Props Based On Generic Value

661 Views Asked by At

I encountered a problem in Typescript that I couldn't find a solution to.

I have a React component, and I want to load it with different props, depending on its "type" prop.

For example:

interface PropsA {
    a: string;
}

interface PropsB {
    b: string;
}

type Props<T extends string> = { type: T } & (T extends 'A' ? PropsA : PropsB);

class Component<T extends string> extends React.Component<Props<T>> {};

So, the expected behavior is - when the type prop equals to "A", I want the component allowed (and required) props to be only 'a' and not 'b'. However, when I try to use this component and set its type to "A", I can render it with the 'b' prop without a problem.

const App = () => {
    return (
        <Component type="A" b="whatever" />
    )
}

** NO ERROR!

However, if I change things a bit, so that the conditional props will render inside another prop, it will work:

type Props<T extends string> = { type: T } & { extraProp: T extends 'A' ? PropsA : PropsB };

class Component<T extends string> extends React.Component<Props<T>> {};

const App = () => {
    return (
        <Component type="A" extraProp={{ b: 'whatever' }} />
    )
}

** ERROR! (this is good, that means I can only use 'a' inside 'extraProp' like I wanted to.

Also, in the Props type, if I change the intersection to union, it will work, but the required prop 'a' or 'b' will now be optional, and that's not what I want.

Why is that so? Is that some bug or am I missing something?

1

There are 1 best solutions below

0
avivyar On

Just found that using:

function Component<T extends string> (props: Props<T>) {
    return null;
}

Instead of:

class Component<T extends string> extends React.Component<Props<T>> {}

Solved the problem. But why? Shouldn't it work also with the class implementation?