MUI中基于SCSS类的可复用TextField组件类型错误排查
问题背景
要封装MUI的TextField为可复用组件,要求使用SCSS模块化类而非styled-components,但封装后出现类型不兼容错误。
非复用版本代码
<InputField id="<id_name>" label="<label>" variant="outlined" inputRef={inputRef} value={value} onChange={(e: React.ChangeEvent<HTMLInputElement>) => { setValue(e.target.value) }} InputProps={{ classes: { root: styles.search__field, // 标准模块化SCSS类 notchedOutline: styles.search__field, // 标准模块化SCSS类 }, }} InputLabelProps={{ classes: { shrink: styles.search__label__focused, // 标准模块化SCSS类 }, }} />
尝试的复用组件代码
import { TextField, type TextFieldProps } from "@mui/material" type InputFieldProps = { rootClass: string borderClass: string shrinkLabelClass: string } & TextFieldProps const InputField = ({ rootClass, borderClass, shrinkLabelClass, InputProps, InputLabelProps, ...restProps }: InputFieldProps) => { return ( <TextField {...restProps} InputProps={{ classes: { root: rootClass, notchedOutline: borderClass, }, }} InputLabelProps={{ classes: { shrink: shrinkLabelClass, }, }} /> ) }
出现的错误信息
The TextField is a convenience wrapper for the most common cases (80%). It cannot be all things to all people, otherwise the API would grow out of control.
Type '{ InputProps: { classes: { root: string; notchedOutline: string; }; }; InputLabelProps: { classes: { shrink: string; }; }; onChange?: ChangeEventHandler<HTMLTextAreaElement | HTMLInputElement> | undefined; ... 284 more ...; onTransitionEndCapture?: TransitionEventHandler<...> | undefined; }' is not assignable to type 'IntrinsicAttributes & TextFieldProps'.
The types of 'InputProps.classes' are incompatible between these types.
Type '{ root: string; notchedOutline: string; }' is not assignable to type 'Partial'.
Property 'notchedOutline' does not exist on type 'Partial'.ts(2322)
错误原因
- 类型不匹配:
TextField的InputProps.classes默认对应InputClasses类型,而notchedOutline是OutlinedInputClasses特有的属性,直接添加会触发类型检查错误。 - 覆盖用户传入的Props:当前写法直接替换了
InputProps和InputLabelProps,没有合并用户可能传入的额外配置,同时类型定义也没有考虑到不同输入变体的类类型。
解决方案
步骤1:导入正确的类类型
从MUI的具体组件导入对应的类类型,匹配outlined变体的需求:
import { TextField, type TextFieldProps } from "@mui/material"; import type { OutlinedInputClasses } from "@mui/material/OutlinedInput"; import type { InputLabelClasses } from "@mui/material/InputLabel";
步骤2:调整Props类型定义
自定义Props的类属性对应正确的类型,同时允许用户传入额外的InputProps和InputLabelProps:
type InputFieldProps = { rootClass: OutlinedInputClasses["root"]; borderClass: OutlinedInputClasses["notchedOutline"]; shrinkLabelClass: InputLabelClasses["shrink"]; } & Omit<TextFieldProps, "InputProps" | "InputLabelProps"> & { InputProps?: Omit<TextFieldProps["InputProps"], "classes"> & { classes?: Partial<OutlinedInputClasses>; }; InputLabelProps?: Omit<TextFieldProps["InputLabelProps"], "classes"> & { classes?: Partial<InputLabelClasses>; }; };
步骤3:合并自定义类与用户传入的类
在组件内部合并自定义的SCSS类和用户可能传入的额外类,避免覆盖:
const InputField = ({ rootClass, borderClass, shrinkLabelClass, InputProps = {}, InputLabelProps = {}, ...restProps }: InputFieldProps) => { return ( <TextField {...restProps} variant="outlined" // 固定为outlined变体,确保类属性生效 InputProps={{ ...InputProps, classes: { root: rootClass, notchedOutline: borderClass, ...InputProps.classes, // 合并用户传入的额外类 }, }} InputLabelProps={{ ...InputLabelProps, classes: { shrink: shrinkLabelClass, ...InputLabelProps.classes, // 合并用户传入的额外类 }, }} /> ); };
说明
- 固定
variant="outlined":因为notchedOutline只在outlined变体下存在,确保组件逻辑与类属性匹配。 - 合并类配置:用户传入的
classes会覆盖自定义的同名类,保留灵活性。 - 精确类型约束:通过
OutlinedInputClasses和InputLabelClasses确保类属性的类型正确性。
内容的提问来源于stack exchange,提问作者Cemal

