Context
I have two components. Props of one component inherit from the props of another one.
declare namespace Props {
interface Fruit {
price: number;
}
interface Banana extends Fruit {
curvature: number;
}
}
declare const Fruit: React.FC<Props.Fruit>;
declare const Banana: React.FC<Props.Banana>;
The facts are:
React.FC is defined by React as just a function of props.Problem
Now, when trying to assign one to another in TypeScript 3.4.0-rc we get:
/**
* ✅ Compile-time error. Function arguments are contravariant.
*/
const fruit: typeof Fruit = Banana;
/**
* ✅ No error. Function arguments are contravariant.
*/
const banana: typeof Banana = Fruit;
/**
* ✅ No errors as expected.
*/
const one: React.ReactComponentElement<typeof Fruit> = <Fruit price={3} />;
/**
* ⁉️ No errors (but expected one). Now it's covariant.
*/
const two: React.ReactComponentElement<typeof Fruit> = <Banana price={3} curvature={15} />
/**
* ⁉️ No errors (but expected one). Now it's contravariant.
*/
const three: React.ReactComponentElement<typeof Banana> = <Fruit price={3} />
/**
* ✅ No errors as expected.
*/
const four: React.ReactComponentElement<typeof Banana> = <Banana price={3} curvature={15} />
Question
Why do two and three not cause an error?
Avoiding JSX and using React.createElement solves this issue.
declare namespace Props {
interface Fruit {
price: number;
}
interface Banana extends Fruit {
curvature: number;
}
}
declare const Fruit: React.FC<Props.Fruit>;
declare const Banana: React.FC<Props.Banana>;
// ✅
const one: React.ReactComponentElement<typeof Fruit> = React.createElement(
Fruit,
{ price: 1000 }
);
// ✅
const two: React.ReactComponentElement<typeof Banana> = React.createElement(
Banana,
{ price: 1000, curvature: 12 }
);
/**
* ✅ Compile-time error.
* Type 'FunctionComponentElement<Banana>' is not assignable to type
* 'ReactComponentElement<FunctionComponent<Fruit>, Pick<PropsWithChildren<Fruit>, "price" | "children">>'.
* ...
* fruits.tsx(10, 5): 'curvature' is declared here.
*/
const three: React.ReactComponentElement<typeof Fruit> = React.createElement(
Banana
);
/**
* ✅ Compile-time error.
* Type 'FunctionComponentElement<Fruit>' is not assignable to type
* 'ReactComponentElement<FunctionComponent<Banana>,
* ...
* Types of property 'propTypes' are incompatible. 🤔
*/
const four: React.ReactComponentElement<typeof Banana> = React.createElement(
Fruit,
{ price: 12 }
);
But it creates another one -- we lose autocomplete on props in VSCode.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With