扩展 MUI 组件时出现 TS 错误,提示“css”属性缺失
我们已使用自定义组件 (MySnackbarContent) 扩展了 SnackbarContent 组件:
export interface MySnackbarContentProps extends Omit<SnackbarContentProps, 'variant'> {
variant?: MyCustomVariant;
type?: MyCustomType;
banner?: boolean;
// ...
}
const MySnackbarContent = forwardRef<HTMLElement, MySnackbarContentProps>(props: MySnackbarContentProps, ref) => {
const { variant = 'normal', type = 'default', banner = false, ...other } = props;
const className = ...;
return <SnackbarContent ref={ref} className={className} {...other} />
}
这是我使用自定义 SnackbarContent 组件时收到的错误:
Property 'css' is missing in type '{ type: "error" | "default" | "success" | undefined; message: string; action: Element; }' but required in type 'Pick<MySnackbarContentProps, "hidden" | "style" | "onSelect" | "slot" | "title" | "className" | "classes" | "innerRef" | "defaultChecked" | "defaultValue" | ... 258 more ... | "actionClickHandler">'.
我不明白为什么
css
属性在这里会出现问题,因为我们没有使用情感或 styled-component(我们使用的是 JSS)。
奇怪的是,当我删除
forwardRef
时,所有类型都得到了正确检查。
缓解此问题的一种可能方法是在
MySnackbarContentProps
中添加
css
属性,并将其设置为类似:
css?: null
。出于某种原因,
css
属性是必需属性。不能 100% 确定为什么这里会出现这种情况。我这里漏掉了什么?
- MUI 版本:4.9.10
- TS 版本:3.6.2
- React:16.13.0
- React 类型:16.9.34
编辑:根本原因解释
尝试了解根本原因时,有三个部分在起作用。
首先,Typescript 允许扩充任何类型,扩充的结果将是合并不同定义中的属性。例如,以下代码:
interface Person {
name: string;
}
interface Person {
age: number;
}
将与编写以下内容相同:
interface Person {
name: string;
age: number
}
这种增强不需要在同一个模块/文件中;因此,项目中的任何模块(包括 node_modules)都可以增强另一个模块中的任何类型)。
其次,Material UI 允许将所有 DOM 属性传递给其许多组件。因此,它本质上是在许多组件中扩展基础
React.DOMAttributes<T>
(例如,Paper 扩展了
React.DOMAttributes<HTMLDivElement>
)。
对我来说,我之所以能够找到问题,是因为我知道
css
是
emotion
的一个属性,而 Storybook 会使用它;因此,我深入挖掘了情绪的作用,并发现了以下内容:
https://github.com/emotion-js/emotion/blob/31e610f2385d5a3dfd532b31f743e5f6b9fee43b/packages/react/types/index.d.ts#L99
因此,情绪通过向
React.DOMAttributes<T>
添加
可选
css
属性来增强它。如果任何类型从此类型扩展,它们将可以访问
css
属性。这足以让我识别罪魁祸首。该库正在导出一个原本要在 Storybook 中使用的实用程序(一些 Storybook 函数正在从这些实用程序中导入)。从输出中删除该组件解决了该问题。如果您正在使用 Storybook,请检查输出的包是否使用了任何 Storybook 组件。
有一件事我没有调查,那就是为什么
css
是一个强制属性,即使情感将 prop 作为可选项传递。
感谢 Gasim 的跟进!
对我来说,根本问题也是由 Storybook 与应用程序捆绑在一起引起的,因为我们使用的 Storybook 文件带有
*.stories.tsx
扩展名。
Typescript 会加载我们设置中的所有
.tsx
文件,进而加载 OP 提到的全局 Emotion 属性增强。
我必须将
"exclude": ["**/*.stories.tsx"]
添加到我们的
tsconfig.json
中才能修复它。