开发者问题收集

扩展 MUI 组件时出现 TS 错误,提示“css”属性缺失

2020-04-30
1670

我们已使用自定义组件 (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
}

Playground

这种增强不需要在同一个模块/文件中;因此,项目中的任何模块(包括 node_modules)都可以增强另一个模块中的任何类型)。

其次,Material UI 允许将所有 DOM 属性传递给其许多组件。因此,它本质上是在许多组件中扩展基础 React.DOMAttributes<T> (例如,Paper 扩展了 React.DOMAttributes<HTMLDivElement> )。

对我来说,我之所以能够找到问题,是因为我知道 cssemotion 的一个属性,而 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 作为可选项传递。

1个回答

感谢 Gasim 的跟进!

对我来说,根本问题也是由 Storybook 与应用程序捆绑在一起引起的,因为我们使用的 Storybook 文件带有 *.stories.tsx 扩展名。 Typescript 会加载我们设置中的所有 .tsx 文件,进而加载 OP 提到的全局 Emotion 属性增强。

我必须将 "exclude": ["**/*.stories.tsx"] 添加到我们的 tsconfig.json 中才能修复它。

tichopad
2022-04-04