Description
I'm trying to answer this Stack Overflow question on typing a React higher-order component. I've been recommending intersections rather than Exclude
for expressing the inner and outer prop types for a higher-order component since TypeScript's type relations and inference seem to handle intersections better than Exclude
in general. (I know this practice has problems; if you know a better way, please let me know! For now, Object.assign
and JSX spreads still generate intersections.) However, React also uses Readonly
for prop types, and I've hit an ugly case in which Readonly
is getting in the way of matching up the intersections between the supplied and expected props. Many simpler cases seem to work OK, but this one fails.
I'm not sure if this is a bug but would like the TypeScript team's feedback on the scenario, since the question has been up on Stack Overflow and I doubt anyone from the TypeScript team will ever look at it there. Hopefully, in consideration of my answering hundreds of TypeScript questions on Stack Overflow and helping triage tens of other issues here, I can have the privilege of occasionally escalating questions I can't answer to the TypeScript team. Thanks!
TypeScript Version: master (8feddcd)
Search Terms: readonly mapped type intersection assignable assignability higher order components
Code
import * as React from "react";
function myHigherOrderComponent<P>(Inner: React.ComponentClass<P & {name: string}>): React.ComponentClass<P> {
return class OuterComponent extends React.Component<P> {
render() {
// Type 'Readonly<{ children?: ReactNode; }> & Readonly<P> & { name: "Matt"; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<Component<P & { name: string; }, any, any>> & Readonly<{ children?: ReactNode; }> & Readonly<P & { name: string; }>'.
// Type 'Readonly<{ children?: ReactNode; }> & Readonly<P> & { name: "Matt"; }' is not assignable to type 'Readonly<P & { name: string; }>'.
return <Inner {...this.props} name="Matt"/>;
}
};
}
Note: if we replace React.ComponentClass
with React.ComponentType
, then the issue does not reproduce due to #27385. This may be why it hasn't been noticed so far.
Expected behavior: No error.
Actual behavior: Error as marked.
Playground Link: Link for non-React example
Related Issues: Possibly #27201