With Typescript and React is it possible the infer a type based on an extra property that I provide along with a functional component?
Here is (a simplified version of) my code:
const openModal = (element) => {
// ...
}
// Define the components with their specific resultType:
const SomeModal: React.FC & { resultType: boolean } = () => <div />;
SomeModal.resultType = true;
const SomeOtherModal: React.FC & { resultType: string } = () => <div />;
SomeOtherModal.resultType = "string";
let someResult = openModal(<SomeModal />);
let someOtherResult = openModal(<SomeOtherModal />);
The code here is simplified but assume that there are a lot of different types of Modals and that openModal has no clue of which type of Modal comes in
Is there a way to infer that someResult wil be a boolean
type and someOtherResult will be a string
type based on the resultType of the element that I’m supplying to openModal?
I’ve tried a lot of options using generics with the openModal function but in all cases the someResult and someOtherResult always had a type of any
or unknown
.
If the type can somehow be infered on the functional component alone (so without using resultType
) that would be even better
Note: I have my code working just fine but it’s the TypeScript that I’m concerned with.
2
Answers
Generics! If I understand your problem correctly, something like this should get you what you’re looking for:
The
T
would be replaced by whatever type you would like to narrow it down to, from your example it would beReact.FC
Heres a link the playground link if you want to mess with it
Unfortunately this is not currently possible in TypeScript with JSX. Even though the components
SomeModal
andSomeOtherModal
have different types, the JSX elements<SomeModal />
and<SomeOtherModal />
have the same type, which isJSX.Element
. So no matter how you write the call signature foropenModal()
, the argument toopenModal()
will not have the information you need. You’re stuck.There is a longstanding open feature request in GitHub at microsoft/TypeScript#14729 to allow some way of distinguishing the type of JSX elements based on their contents. Maybe someday it will be implemented, and the chance of that presumably increases with an increase in community demand. So anyone who wants to see this happen might like to go to that issue and give it a 👍. But until and unless such a feature is introduced, you can’t do this with JSX.
You might work around it by giving up on JSX and calling
createElement()
instead, at which point you could use module augmentation to overloadcreateElement()
such that the information you care about is propagated:That’s just one possible way to do that; presumably
__resultType
will not really be present at runtime (but neither isresultType
in your example code). And then yoursomeModal
could use that propagated information:And finally your code behaves as expect if you give up on JSX:
Playground link to code