I'm trying to use generics and interface to make React component.
interface MyAtomComponent {
<P>(props: P): React.ReactElement;
WithSomeOption: <P>(props: P): React.ReactElement;
}
// component definition
const MyAtomComponent: MyAtomComponent = <P,>(props: P) => { ... };
MyAtomComponent.WithSomeOption = <P,>(props: P) => { ... };
// in use
<MyAtomComponent<{/* something */}> />
<MyAtomComponent.WithSomeOption<{/* something */}> />
It looks good, but problem occurs in this case:
type MoleculeProps = {/* molecule prop */} & MyAtomComponent['WithSomeOption'] // Generic of WithSomeOption is gone
const Molecule = ({...}: MoleculeProps<number>) => { ... }; // I cannot put `number` because MoleculeProps is not generic
I tried like this:
type AtomPropsWithGeneric = MyAtomComponent['WithSomeOption'];
// AtomPropsWithGeneric is now <P>(props: P): React.ReactElement
const Test: AtomPropsWithGeneric<{}> = ... // AtomPropsWithGeneric is not generic.
and also this failed too:
type AtomPropsWithGeneric<P> = MyAtomComponent['WithSomeOption']<P>; // ';' expected
I think []
in type cannot extract generic; typeof
also print same error(';' expected
).
Is any way to extract generic type in interface?
stack overflow suggested this answer but I think this case is little bit different.
You can use instantiation expressions (#47607):
type WithSomeOption<P> = typeof MyAtomComponent.WithSomeOption<P>;
It's very important to use dotted access instead of bracket notation, as the latter will not parse:
// not valid TS
type WithSomeOption<P> = typeof MyAtomComponent["WithSomeOption"]<P>;
We also need typeof
since dotted access on interfaces is disallowed (or else it could be mistaken for a namespace):
// will error; "Cannot access 'MyAtomComponent.WithSomeOption' because 'MyAtomComponent' is a type, but not a namespace."
type WithSomeOption<P> = MyAtomComponent.WithSomeOption<P>;