javascript - Warum funktioniert das Verbreiten von Eigenschaften innerhalb von Grid, aber nicht in FormControl?
Sandbox hier: https://codesandbox.io/s/agitated-ardinghelli-fnoj15?file=/src/temp4.tsx:0-1206.
import { FormControl, FormControlProps, Grid, GridProps } from "@mui/material";
interface ICustomControlProps {
gridProps?: GridProps;
formControlProps?: FormControlProps;
}
const CustomControl = (props: ICustomControlProps) => {
return (
<Grid {...props.gridProps}>
<FormControl {...props.formControlProps} />
</Grid>
);
};
const CustomControlVariant1 = (props: ICustomControlProps) => {
return (
<CustomControl
/**
* Below gridProps is of type GridProps.
* It is set to object with some fixed (item, xs, sm, md) properties and spreaded props.gridProps
* (which is of type GridProps).
* But doing exactly same with formControlProps doesnt work: setting fixed component properties
* and spreaded props.formControlProps
*/
gridProps={{ item: true, xs: 12, sm: 12, md: 12, ...props.gridProps }}
formControlProps={{
component: "fieldset", /** ERROR: Type '{ children?: React.ReactNode; classes?: Partial<FormControlClasses> &
* Partial<ClassNameMap<never>>; color?: "error" | ... 4 more ... | "warning"; ...
* 264 more ...; component: string; }' is not assignable to type 'FormControlProps<"div", {}>'.
* Object literal may only specify known properties, and 'component' does not exist in type
* 'FormControlProps<"div", {}>'.
*
* Object literal may only specify known properties, and 'component'
* does not exist in type 'FormControlProps<"div", {}>'.ts(2322)
*/
...props.formControlProps
}}
/>
);
};
Update
Beachten Sie, dass das Hinzufügen einer weiteren Ebene der Verteilung für FormControl funktioniert:
<CustomControl
gridProps={{ item: true, xs: 12, sm: 12, md: 12, ...props.gridProps }}
// this works!! So, `component` is indeed on `FormControlProps`
// which can be confirmed here: https://mui.com/api/form-control/#props
formControlProps={{
...{
component: "fieldset",
...props.formControlProps
}
}}
/>
Hier ist die Sandbox für diesen Code.
Ich finde beide Ansätze logisch korrekt und meiner Meinung nach sollten beide funktionieren, aber ich verstehe nicht, warum der erste einen Fehler gibt.
Antwort #1
Kurzfassung;
Um TypeScript zufrieden zu stellen, könnten Sie ICustomControlProps wie folgt ändern:
interface ICustomControlProps {
gridProps?: GridProps;
formControlProps?: FormControlProps & { component: React.ElementType };
}
Erklärung
Schauen wir uns die Deklarationsdatei von FormControl an:
declare const FormControl: OverridableComponent<FormControlTypeMap>;
export type FormControlProps<
D extends React.ElementType = FormControlTypeMap['defaultComponent'],
P = {},
> = OverrideProps<FormControlTypeMap<P, D>, D>;
Kurz gesagt, FormControlProps fasst die Props der Standardkomponente zusammen (die ist ein div - also einige Props, die ein bestimmtes DOM-Element aufnehmen kann) und die Props, die die FormControl-Komponente definieren (diese sind in FormControlTypeMap zu finden, z. B. classes, fullWidth, hiddenLabel usw.).
In FormControlTypeMap gibt es sicher keine definierte component-Eigenschaft und daher der Fehler. Allerdings sagt OverridableComponent<FormControlTypeMap>, dass das Empfangen einer component-Prop akzeptiert wird:
export interface OverridableComponent<M extends OverridableTypeMap> {
<C extends React.ElementType>(
props: {
/**
* The component used for the root node.
* Either a string to use a HTML element or a component.
*/
component: C;
} & OverrideProps<M, C>,
): JSX.Element;
(props: DefaultComponentProps<M>): JSX.Element;
}
Also können Sie sicher FormControl so verwenden: <FormControl component={...} />, aber es in einer anderen Komponente umschließen, wie folgt:
interface ICustomControlProps {
gridProps?: GridProps;
formControlProps?: FormControlProps;
}
const CustomControl = (props: ICustomControlProps) => {
return (
<Grid {...props.gridProps}>
<FormControl {...props.formControlProps} />
</Grid>
);
};
erfordert von Ihnen, dass Sie angeben, dass ein component-Prop auch auf ICustomControlProps.formControlProps erlaubt ist:
interface ICustomControlProps {
gridProps?: GridProps;
formControlProps?: FormControlProps & { component: React.ElementType };
}
Warum das funktioniert:
formControlProps={{
...{
component: "fieldset",
...props.formControlProps
}
}}
Die Antwort scheint in diesem Problem gefunden zu werden, genauer gesagt in diesem Kommentar, der sagt, dass ... einen Subtyp erstellt, also ist alles gültig.
