Material-ui: 可以简化类型以提高性能吗?

创建于 2020-01-07  ·  70评论  ·  资料来源: mui-org/material-ui

正如@eps1lon在#18128 中所建议的那样,我创建这个问题是为了讨论 Material-UI 类型以及是否可以简化它们以减少检查它们所花费的时间,尤其是在编辑期间。

拥有最精确的类型(提供最好的错误和编辑器完成)和快速的类型检查(范围的远端是any )之间总是存在紧张关系。
https://github.com/microsoft/TypeScript/issues/34801这样的问题表明 Material-UI 可能会从放宽准确性中受益,以恢复一些性能。

从我到目前为止调查的 repro 来看,很多缓慢似乎来自大量的 CSS 属性名称(参见 https://github.com/mui-org/material-ui/blob/master/packages/ material-ui-styles/src/withStyles/withStyles.d.ts)。 我自己不是一个活跃的 CSS 用户,我有一些幼稚的问题:

1) 我是否正确地假设为每个众所周知的 CSS 属性都有一个名称和类型是非常有价值的,而且我们不能放弃?
2) CSSProperties类型似乎支持“伪选择器和媒体查询”,根据我的有限阅读,它似乎被命名为附加 CSS 属性的包。
a) 这些包本身是递归的还是只有一个附加层? 也就是说,你是从widthfoo.width还是foo.bar.width等等? 如果它只是一个级别,简化类型会将我的本地复制从 4.6 秒减少到 3.6 秒(即大赢)。
b) 我自己玩弄这些类型,但想不出比BaseCSSProperties[keyof BaseCSSProperties]更好的东西,但是 - 我猜你知道 - 这不是一个非常有用的类型。 它基本上是说任何 CSS 属性都可以具有任何(其他)CSS 属性的类型 - 这仅比any略好。
3) 在StyleRules ,如果没有属性,您会得到CSSProperties() => CSSProperties (我会草率地称之为“thunked CSSProperties”),这是有道理的 - CSSProperties可能很懒。 如果有属性,你会得到CreateCSSProperties<Props> ,这是有道理的 - Props可能需要计算CSSProperties - 或(props: Props) => CreateCSSProperties<Props> ,我没有不明白,因为它实际上是双重懒惰的 - 您已经传入Props一次以获得CreateCSSProperties ,然后再次获得单个属性。 为什么它是“双重重击”?

另外,我怀疑,但尚未证明IsEmptyInterface对于它提供的好处来说太贵了。 但是,我很可能不完全了解这些好处,因此了解更多信息会有所帮助。

我们能否共同努力在准确性和性能之间找到正确的平衡点? (注意:“只是让编译器更快”显然是一个可行的策略,但我想在我们优化它们之前将类型放到一个好的位置。)谢谢!

performance typescript

最有用的评论

我今天开始将 Material UI ( 4.9.4 ) 添加到我的项目中,而且速度下降真的非常严重,我认为我什至无法在我的项目中使用它。 刚刚添加了一个简单的<Slider/>组件,使用withStyles()自定义。

我们正在谈论从我的 IDE 中的即时 TypeScript 反馈到有时感觉像 5-10 秒(对于我现在甚至不与 Material UI 交互的部分代码 - 它只是使用的文件中的 TypeScript 完全减慢组件)。 这些类型肯定有明显的错误(或者是的,过于复杂),似乎@amcasey正在做一些很好的调查 - 我希望你能深入了解它!

试图找到一种方法,我至少可以暂时排除@material-ui所有 TypeScript 内容(基本上使整个模块any ) - 但 TypeScript 似乎并没有让这变得足够容易。

所有70条评论

我不熟悉 material-ui 类型,但尝试回答这些问题。

  1. 是的,完全支持实际 Web 标准中声明的所有 css 属性很有用。
  2. a) 在我们的例子中,我们从不使用超过 2 的深度,但是像这样的情况很有可能
    ```打字稿
    const 样式 = (主题: 主题) =>
    创建样式({
    某个div:{
    '&:悬停按钮':{
    可见性:'可见',
    不透明度:1,
                ':after': {
                    content: 'x',

                    [theme.breakpoints.up('lg')]: {
                        content: 'close',
                    },
                }
            },
        }
    });
```
b) I do not understand why `BaseCSSProperties[keyof BaseCSSProperties]` is needed there

  1. 我认为(props: Props) => CreateCSSProperties<Props>是不需要的,我们在我们的 material-ui 类型版本中排除了这种类型,并没有发生任何不好的事情。

可能值得看看 3.9.3 版本中类型的实现,因为在这个版本中,类型检查足够快,打字也很好。

首先,我要感谢您伸出手来调查此事。 让某人对类型的哪些部分慢或慢进行基准测试是非常有帮助的。

  1. 我是否正确地假设每个众所周知的 CSS 属性都有一个名称和类型是非常有价值的,而且我们不能放弃?

在这里不可能做到不偏不倚。 尽管着眼于更广泛的生态系统,但我认为我们不能放弃它。 Chrome devtools 有这个功能,react 自己用CSSProperties等输入style道具。我看不到自己从 IDE 切换到浏览器并检查它是文本装饰还是字体装饰或文本转换。

  1. [...]
    这些包本身是递归的还是只有一个附加层?

我需要检查我们正在使用的 CSS-in-JS 解决方案。 从技术上讲,CSS 中的媒体查询可以是递归的。 我愿意减少这种递归性,看看我们是否会收到报告。 技术上嵌套的媒体查询可以使用and运算符进行扁平化。 不过,我们应该将其限制为两个级别:一个用于媒体查询,另一个用于伪选择器。 这仍应进行类型检查 IMO:

const styles = {
  root: {
    '<strong i="18">@media</strong> (max-width: 12cm)': {
      ':hover': {}
    }    
  }
}

这是你看到自己在写@oliviertassinari 的东西吗?

  1. [...]
    CSSProperties - 或 (props: Props) => CreateCSSProperties,我不明白,因为它实际上是双重懒惰的 - 您已经传入 Props 一次以获取 CreateCSSProperties 然后再次获取单个属性。 为什么它是“双重重击”?

如果参数本身不是一个属性包而是一个函数,那么它需要一个主题。 样式可以取决于两种不同类型的属性包:主题(可通过 React 的上下文 API 获得)或道具(直接传递给组件):

makeStyles({ root: { color: 'blue' }}); // A
makeStyles(theme => ({ root: { color: theme.color } })); // B
makeStyles({ root: props => ({ color: props.color})}); // C
makeStyles({ root: { color: props => props.color } }); // D: same as C, only exists for dev ergonomics
makeStyles(theme => ({ root: props => ({ color: props.color || theme.color }) })); // E: what you called "double-lazy"

这不是关于提高性能的惰性评估,而是关于必须等待上下文和道具可用。

另外,我怀疑,但尚未证明 IsEmptyInterface 对于它提供的好处来说太昂贵了。 但是,我很可能不完全了解这些好处,因此了解更多信息会有所帮助。

有一种情况会使用它:

考虑

const useStaticStyles = makeStyles({ root: { color: 'blue' } });
const useDynamicStyles= makeStyles({ root: { color: props =>  props.color } })
function Component() {
  const staticClasses = useStaticStyles(); // No error
  const throwingClasses = useDynamicStyles(); // $ExpectError
  const dynamicClasses = useDynamicStyles({ color: 'blue' });
}

推断从makeStyles返回的函数的调用签名(即名为useSomeStyles的钩子)。 我们需要检查传递给makeStyles包是什么样式的。 我们已经有了一个助手来推断样式包中使用的道具类型。 如果样式包是静态的,即 TS 推断{}类型。 然后我们使用IsEmptyInterface检查 Props 的推断类型,对于一个分支,我们使用带有 0 个参数的调用签名,而对于另一个分支,我们使用一个带有 1 个参数的调用签名,该调用签名等于推断的 props 类型(见StylesRequirePropsStylesHook

简而言之:我们避免编写useStaticStyles({})useStaticStyles(null as any) 。 它在https://github.com/mui-org/material-ui/pull/14019中引入以关闭https://github.com/mui-org/material-ui/issues/14018。 我想我们可以短路确定呼叫签名。 也许重载调用签名而不是使用条件类型?

这个“功能”的问题在于,如果高级用户理解原因,他们在使用null as any时不会有问题。 即使不需要,甚至传递一个空对象也可以。 然而,当不习惯 Material-UI 或 TypeScript 时,它会非常混乱/令人沮丧。 尤其是因为大多数造型无论如何都不是基于道具。

似乎大部分时间类型检查器都在忙于样式解决方案? 我会期望我们的组件的调用签名,即大部分时间可能需要什么道具。

我可以抓取更多存储库以专门查看withStylesmakeStyles 。 到目前为止,我只看过道具的使用。

这是你看到自己在写@oliviertassinari 的东西吗?

@eps1lon我们在代码库中出现了几次这种嵌套(例如<strong i="8">@media</strong> (hover: none) )。 但是对于核心组件来说不是很频繁。 我想这是同一个用户空间。 这绝对是权衡的一部分。

@beholderrk

  1. 我想了很多,但还是想问问。
  2. a) 深度二应该是可以表达的——只是比深度一多一点重复。
    b) 我花了很长时间才弄明白这个问题,我希望我能亲自解释它,而不是用文字来解释。 基本上,索引签名是说所有属性都具有相同的类型。 只有当它指定了一种适用于所有这些的类型时才有效。 一种方法是构造所有属性类型的联合, BaseCSSProperties[keyof BaseCSSProperties] - 那么每个属性都有一个兼容的类型。 例如,假设您在 CSS 中可以拥有的唯一属性是name: stringwidth: number 。 指定适用于这两个属性的索引签名的一种方法是说每个属性都是string | number 。 这不是很好 - name永远不会是number并且width永远不会是string - 但它有效。 真正的问题是您想要的东西实际上无法表达(至少,就我们已经能够确定的而言 - 可能有一个“聪明的”黑客可以做到这一点)。 您实际上想说您的类型包含name: stringwidth: numberx: CSSProperties ,其中x不是namewidth - 这是缺少的“除此之外的任何东西”。 我希望这更清楚一点。
  3. 听起来@eps1lon 对此有话要说,但我仍在解析他的回复。

已知良好的基线将非常有帮助。 你碰巧有链接吗?
编辑:找到了。

@eps1lon 很高兴参与对话。 快速、正确的类型对每个人都有好处。 😄

  1. 这里没有争论——我只是想我会早点问,因为这会缩短整个谈话的时间。
  2. 两层似乎是可行的(值得注意的是,这些类型仍然在很大程度上无用)。 我会看看我是否可以起草一些东西。
  3. 由于我缺乏上下文,不清楚主题和道具是否不同。 如果是,那么结构就有意义。 谢谢澄清。

关于isEmptyInterface ,您能否将属性参数设置为(例如) useStaticStyles可选? 从某种意义上说,调用者可以在预期时省略它们,这将不太正确,但键入检查会便宜得多。 正如我所说,我没有数字或任何东西给你——这只是我的猜测。

你对2(b)有什么看法? 似乎该类型没有提供太多价值,因为它基本上表示将接受任何属性名称,并且返回类型可以是众多事物之一。

关于isEmptyInterface,您能否将属性参数设置为(例如)useStaticStyles 可选?

我想先尝试重载调用签名,看看这是否有任何影响。 然后我们将尝试通过使其始终可选来减少声音。 让它听起来比平常更安全,因为几乎所有用例都只调用一次,所以你可能只会犯一次错误,而且很快就会出现。 如果它没有给我们带来太多的性能,那么出售它会很困难。 我将使用为原始问题创建的存储库 (https://github.com/microsoft/TypeScript/issues/34801#issue-514055289)。

你对2(b)有什么看法? 似乎该类型没有提供太多价值,因为它基本上表示将接受任何属性名称,并且返回类型可以是众多事物之一。

不小心跳过了。 我会在 IsEmptyInterface 实验之后研究它。

@eps1lon完全同意 - 如果消除它不是一个实质性的性能胜利,请保留isEmptyInterface

在#19320 中,我们摆脱了一些复杂的条件类型,其中函数重载确实实现了相同的目标(删除了IsEmptyInterface和任何布尔逻辑类型)。 尽管除了代码更少之外,这似乎并没有给我们带来太多好处。

我想补充一点,我目前正在 TS 3.2.4 和 3.7.4 之间来回切换。 与 3.2.4 相比,我们的类型测试套件在 3.7.4 中的运行速度慢了 50%(~90s vs 50s)。

我将继续研究我们是否可以限制 CSSProperties 的深度并完全取消对媒体查询和伪选择器的支持。 虽然没有输入那些并不是真正的选择。 类型检查器应该能够在合理的时间内检查这些。

类型检查器可能是实际的瓶颈。 也许我们可以调查一下 perf 是哪个版本的。

如果您将在 3.2.4 和 3.7.4 中运行的命令发送给我,我可以在本地进行分析。 然而,经验表明,原因可能是自 3.2.4 以来添加的额外的、可取的检查。 (我假设“0s”是一个错字——可能是“40s”或“50s”?)

关于 CSSProperties,我同意保留属性名称和类型非常有价值。 但是,我认为除了在合理的时间内检查它们之外还有更多的事情 - 第一个问题是类型系统实际上无法表达您想要的形状。 我想我们可能会花一些时间来研究该问题的一般解决方案 - 我可以假设您有兴趣参与该讨论吗?

我们有用于比较编译器的多个版本的脚本,因此,如果您能确定您希望我们运行的相当稳定的测试,我们可以绘制出随时间推移的减速情况。

(我假设“0s”是一个错字——可能是“40s”或“50s”?)

抱歉,现在是 50 年代。

如果您将在 3.2.4 和 3.7.4 中运行的命令发送给我,我可以在本地进行分析。

它只是根目录中的yarn typescript ,它在实现它的每个工作区中运行相同的命令。 例如yarn workspace @material-ui/styles run typescripttslintdtslint$ExpectError测试我们的类型。 在 3.7.4 中,我们遇到了一些失败,不得不调整我们的测试(参见 #19242)

第一个问题是类型系统实际上不能表达你想要的形状。

我也怀疑过。 看起来我们将“具体”形状与具有索引签名的对象混合的方式只是一种解决方法。

我可以假设您有兴趣参与该讨论吗?

确实。 我将花更多时间在非递归 CSSProperties 上,然后编写更多测试来说明我们在这些类型中寻找什么。 我怀疑其他 css-in-js 样式解决方案也遇到了类似的性能瓶颈。

我明天会尝试这些命令(我想我应该提到我在太平洋时间并遵守美国假期)。

看起来我们将“具体”形状与具有索引签名的对象混合的方式只是一种解决方法。

谢谢,我一直在努力寻找如何最好地表达这一点。 是的,您是正确的,索引签名没有做您想要的。 我们对可能的变体有一些想法,但我们需要探索性能影响。

我怀疑其他 css-in-js 样式解决方案也遇到了类似的性能瓶颈。

非常如此。 我们希望我们为您所做的任何事情都可以推广到改善整个生态系统。

我觉得我错过了一些明显的东西,但我目前被卡住了。 首先,我放弃了 Windows - 事情似乎在 Linux 上运行得更好。 如果你想深入研究,请告诉我。 其次,我可以让yarn typescript运行 - 据我所知,干净利落 - 但它似乎在运行 tslint,而不是纯 tsc。 当我在同一个 tsconfig.json 上运行 tsc 时(我专门用样式测试),我得到了大约 40 个错误。 我究竟做错了什么? 出于分析目的,将 repro 简化为单个 tsc 调用将非常有帮助。

@amcasey yarn typescript不是关于编译而是测试我们的类型。 我们正在使用与绝对类型存储库中使用的设置类似的设置。 packages/*中的 TypeScript 文件几乎总是一堆应该通过或失败的语句,我们用$ExpectError捕获它们。

我认为最好的“真实世界”测试用例是在您将skipLibCheck: truenoEmit: true./docs/tsconfig.json之后通过yarn workspace docs run tsc -p tsconfig.json tsc在我们的文档中使用./docs/tsconfig.json :

--- a/docs/tsconfig.json
+++ b/docs/tsconfig.json
@@ -3,6 +3,8 @@
   "include": ["types", "src/pages/**/*"],
   "compilerOptions": {
     "allowJs": false,
-    "noUnusedLocals": true
+    "noUnusedLocals": true,
+    "noEmit": true,
+    "skipLibCheck": true
   }
 }

@eps1lon感谢您的澄清。 我对 tslint 变慢并不感到兴奋,但我想一次只关注一个变量。 我将使用您建议的各种版本的打字稿运行文档构建,看看是否有任何内容跳出。 谢谢!

这个设置是完美的。 我看到检查时间在 3.3 和 3.4 之间翻了一番。

| 版本 | 检查时间 |
|-|-|
| 3.2 | 16.71s |
| 3.3 | 16.79s |
| 3.4 | 35.25s |
| 3.5 | 21.40s |
| 3.6 | 23.10s |
| 3.7 | 27.39s |

我会再挖一点,但有人告诉我,条件类型的 3.3 实现不完整,3.4 实现很慢,而 3.5 实现很好。 因此,不幸的是,这可能是意料之中的。

具体来说,我怀疑此更改引入了此错误中所述的减速。

我发现在 3.5 和 3.7 之间运行检查所需的时间增加了 6 秒。 这看起来相当可观。

@embeddedt这些数字来自每个版本的单次运行,所以可能会有相当多的噪音。 不过,我会深入挖掘,看看能不能找到任何东西。

我在 Linux VM 上重做了它,3.7 始终比 3.5 慢 20-25%。

这已被证明是很难一分为二的,因为相同构建的连续运行相差约 5%,而 3.5 和 3.6 之间或 3.6 和 3.7 之间的差异仅为约 10%。

我注意到的一件可疑的事情是styled-components为 TS >= 3.7 提供了单独的 .d.ts 文件,因此比较可能不是苹果对苹果的比较。

令我惊讶的是,新的styled-components类型似乎更快。 不过,将苹果与苹果进行比较仍然会使调查更容易。

我想不出一个聪明的解决方案,所以我将通过合并绘制编译时间合并并寻找尖峰。 我希望明天有数字。

@amcasey感谢您为调查此事所做的努力! 看到 TS 团队的成员和 Material UI 一起工作真的很棒。 我偶然发现了这个 Github 问题,试图弄清楚为什么我们的 Material UI 编辑器体验如此缓慢(我们在两个工作项目中使用它)。 可以肯定的是,我们在 VsCode 中看到了智能感知和可用性方面的重大影响。

在这一点上,我们很乐意在我们的 JSS 中交换一点类型安全性,以换取库其余部分的快速反馈。 有时在 Typescript 服务器赶上代码更改之前需要等待 8-10 秒

即使使用三轮平均值,数据也非常嘈杂。 然而,似乎是在运行时明显下降,在https://github.com/microsoft/TypeScript/commit/ad322a561a301ae357da051b9221b2222c13be36在显着增加(返回到大致先前的水平) https://github.com/microsoft/TypeScript /commit/480b73915fdd805952fd355e4cf3e1bc803e0878以及https://github.com/microsoft/TypeScript/commit/c5e6d95e93032864a48e93039648e95e9303648e95e93039348e93034848e93039648e9303934848e73915fdd805915fdd805952fd805952fd355e4cf3e1bc803e0878 的一个特殊峰值我将专注于前两个,直到我运行更多测试以确认总体上升趋势(如何每次提交都变得更糟?)。

上升趋势经得起推敲,我不知道是什么导致了这种情况。 也许离散的减速非常接近,以至于噪音使它们看起来像一条曲线。

我每次提交最多运行 10 次,现在在倾斜区域有四个不同的回归。 :微笑:

https://github.com/microsoft/TypeScript/commit/26caa3793e310e271ddee8adc1804486e5b0749f(~700ms
https://github.com/microsoft/TypeScript/commit/250d5a8229e17342f36fe52545bb68140db96a2e(~500ms
https://github.com/microsoft/TypeScript/commit/7ce793c5b8c621af5ce50af0ca3958c7bd6541bf(~1300ms
https://github.com/microsoft/TypeScript/commit/28050d5c47c6cd7627555f12cf13b1062f80322a(~400ms

(回归开始前的总时间约为 33 秒。)

只是为了稍微降低预期:这些回归中的一些很可能会成为有价值的额外检查,即使我们设法免费获得所有这些检查,我们仍然只能享受 20% 的折扣“太长了”。

编辑:我已经更新了链接。 因为我在时间倒退,我感到困惑并标记了每次回归之前的合并。

@eps1lon@ts-ignore可能会有所帮助。 基本上,当检测到错误时,假设用户的首要任务是获取有关错误的良好信息,因此可能会完成一些额外的工作。 如果该信息随后被丢弃(因为@ts-ignore ),那么该时间只是浪费了。 (不幸的是,检测不需要检测的错误并不简单。)另一种策略是添加显式类型断言(包括到any ),直到编译器停止抱怨。

@eps1lon@ts-ignore可能会有所帮助。

我们在docs/只有一个用法。 为了以防万一,我还是删除了它:#19504

老实说,在这种情况下,听起来@ts-ignore是一种反模式。 它不仅没有给你有用的信息,即我们有什么样的错误,而且它还是一个性能瓶颈。

据我所知, @ts-ignore仅在进行类型检查的.js文件中有用。

嗯,这几乎肯定不能解释为什么 PR 改进错误消息会降低性能。 不过看起来确实有改进。 😄

我对 TypeScript 的世界很陌生,尤其是在 JS 中的样式解决方案方面,但上个月我一直在悄悄关注这个帖子,我很想听听人们对潜在解决方法的想法,在至少在短期内。

我假设某些用户(我自己就是其中之一)不会大量使用内置样式系统,或者完全避免使用它。 我这样做主要是因为我更熟悉纯 CSS 或 Sass,而且我还没有真正有时间深入研究如何有效地使用 JS 样式系统。 我更喜欢自己编造类名,编写一个单独的样式表文件,在我的 React 组件中使用类名并继续。 本质上,我的风格就像我在编写纯 HTML 一样。

话虽如此,添加一个标志来关闭样式系统的昂贵部分的类型检查(可能通过有条件地执行诸如type CSSProperties = any类的事情)是否可能/实际? 我不知道使用样式系统与不使用样式系统的人数统计数据,但我认为它不会真正造成太大伤害(前提是添加了检查以测试具有该标志集的类型) ,这将是一种提高至少一部分用户性能的快速方法。

只是想提一下总体思路; 随意将其击落。 :slightly_smiling_face:

@embeddedt一般来说,将某些内容显式标记为any是禁用该符号的类型检查的好方法。 话虽如此,我不记得您是否可以只破坏先前的声明,或者更确切地说,正如您所建议的,您需要编译器支持以避免重复声明问题。

新数字(不同的机器,不同的时间指标):

| 版本 | 总时间 |
|-|-|
| 3.5.3 | 32.5s |
| 3.7.5 | 35.9s |
| 大师| 29.9s |

我上面发布的一些问题仍然存在,但我们基本上回到了 3.5 perf(对于这个基准)。 显然,它仍然比我们希望的要慢得多,但是下一批更改很可能会在 material-ui 方面进行。

在我们的测试套件上测试了 3.8.1,看起来它们和之前使用 3.2.4 的一样快(3.7 明显慢得多)。

坦率地说,我无法相信我们能够在不放弃新功能的情况下收回多少性能。 :smile: 我认为可能会有更多的松懈(例如 https://github.com/microsoft/TypeScript/pull/36754),但我仍然怀疑最有影响的更改将是 CSSProperties 类型的简化。 你有机会和那些玩吗? 似乎至少有一部分用户(例如@embeddedt)愿意放弃某些类型检查以换取性能胜利。

似乎至少有一部分用户(例如@embeddedt)很乐意放弃某些类型检查以换取性能胜利

TS 团队的某个人最近不是刚刚在推特上说,对于每个想要更严格类型的用户,都有一个想要更宽松的类型吗? :微笑:

对我来说,这与类型检查无关(浏览器开发工具具有更好的检查 CSS 的能力)。 更重要的是提供自动完成功能。

我会尝试不同的“版本”,看看它们是如何做的。

@amcasey我不认为 CSSProperties(在样式组件中称为 CSSObject)的递归性质是主要问题。 否则他们的表现会和我们一样糟糕。 请参阅https://github.com/eps1lon/mui-types-perf/pull/6基准日志

我们所做的“超载”数量可能更多是一个问题。 styled-components只允许静态对象,而我们允许 thunked 版本以及每个属性都是 thunk。 我不确定。

我很想简化类型签名(因为 IMO 也更容易让开发人员掌握),但我被明确要求匹配 JSS 实现。 现在我们支持它,我们不能轻易回滚。 特别是如果增益在 20% 区域内。 我不认为这证明破损是合理的。

类型是否可以有条件地降低准确度(基于用户设置)? 这不应该破坏任何现有代码(因为默认情况下可以关闭设置),并且可以让像我这样不需要复杂类型的用户快速看到性能提升。

将使像我这样不需要复杂类型的用户能够快速看到性能提升。

甚至没有确认您会获得显着差异。 我已经看到 15% 的性能获胜,但是否可以识别这是值得怀疑的。

我可以看到的“用户设置”是在安装时修补软件包。 我们没有足够的带宽来维护多个版本的类型。

@eps1lon抱歉,我想我的问题可能不清楚。 我认为CSSProperties很好(不过,显然,如果它更小会更快) - 我实际上希望可能有空间来简化https://github.com/mui-org 中的子类型将此类型更改为any ,您会得到更少的完成吗?

编辑:在我的盒子上,这使得编译docs项目的速度提高了 15%(29.7 秒到 25.5 秒),但我不知道对编辑体验的影响。
编辑 2:实际上,一旦您放弃在类型的递归部分折叠,您就可以使用BaseCreateCSSProperties并且任何其他属性都将具有any (即您可以保留CSS 属性的真实类型)。
编辑 3:由于过多的属性检查(即对象文字中不允许使用任意属性名称),编辑 2 不起作用。

你关于完成与类型检查的观点非常有趣,因为我假设某些类型的作者可能会有这种感觉。 @DanielRosenwasser我想我们考虑过做这样的事情来适应模式"a" | "b" | string - 有没有去任何地方?

另请注意, styled-components存在(我们认为)密切相关的检查器性能问题。

关于能够更准确地指定类型,我已经提交了https://github.com/microsoft/TypeScript/issues/36782。

看起来emotion可能在同一条船上。

我今天开始将 Material UI ( 4.9.4 ) 添加到我的项目中,而且速度下降真的非常严重,我认为我什至无法在我的项目中使用它。 刚刚添加了一个简单的<Slider/>组件,使用withStyles()自定义。

我们正在谈论从我的 IDE 中的即时 TypeScript 反馈到有时感觉像 5-10 秒(对于我现在甚至不与 Material UI 交互的部分代码 - 它只是使用的文件中的 TypeScript 完全减慢组件)。 这些类型肯定有明显的错误(或者是的,过于复杂),似乎@amcasey正在做一些很好的调查 - 我希望你能深入了解它!

试图找到一种方法,我至少可以暂时排除@material-ui所有 TypeScript 内容(基本上使整个模块any ) - 但 TypeScript 似乎并没有让这变得足够容易。

@lostpebble通过使用withStyles以外的其他东西来自定义滑块,例如 CSS 模块,是否会发生同样的情况?

@lostpebble我们目前没有支持的方法来排除一组特定的类型。 如果你真的,真的想要,要试验的就是路径映射。 您可以尝试像"@material-ui/*": ["simplemui"]这样的路径映射,然后创建一个simplemui.d.ts包含

declare const x: any;
export = x;

这将有效地使所有 material-ui 类型any 。 这绝对是一个 hack,而不是我可以推荐的东西,但它可能会解锁您的编辑体验。

我认为我们已经做出了一些很好的改进(在 30% 区域的某个地方),但看起来我们现在能做的就是让打字更宽松。

这绝对需要具体的建议,例如您可以接受哪些错误的代码被类型检查器接受。 然后我们需要进行基准测试,看看这是否会产生有意义的影响。

您必须了解故意引入的回归为维护人员增加了大量工作,因为我们必须向图书馆消费者解释这一点,并且总体上压力很大。

所以这不是我目前的优先事项,除非有人有可操作的情报。 否则,我必须投入太多时间,而回报却很少。

在我的情况下makeStyles(theme => createStyles(...)) ,从createStyles(...)返回Record<ClassKey, any>几乎~一半~(在我的代码和计算机中,大约~1200ms -> 750ms~ 1400ms → 1100ms) encodedSemanticClassifications-full: elapsed time显示在 tsserver 日志中(它看起来不是一项昂贵的工作,但可能正在等待类型检查完成)。

export default function createStyles<ClassKey extends string, Props extends {}>(
  styles: StyleRules<Props, ClassKey>,
): Record<ClassKey, any>;

createStyles(...)检查样式结构,因此我们可以跳过 makeStyles 的参数类型大规模联合与 createStyles 的大规模联合的返回类型的类型检查。

~(并注释掉整个 makeStyles 代码:650 毫秒)~

只有没有const断言的打字稿版本才需要@ypresto createStyles 。 如果您可以在代码库中使用{ display: 'block' as const } (ts >= 3.4),那么在createStyles

@eps1lon我们注意到了这一点,并尝试在docs进行切换,但结果并不令人印象深刻。

@eps1lon带有const并且没有createStyles ,IntelliSense 不再显示上下文感知的候选对象 :cry:

@ypresto它应该。 你有一个示例代码片段吗?

@amcasey

as const到外部对象或属性会有效地杀死它。 我不想把它放在每个属性上。

const useStyles = makeStyles(theme => ({
  root: {
    // no IntelliSense
  }
} as const))

同样没有 createStyles 它对字符串完成的限制很小。

const useStyles = makeStyles(theme => ({
  root: {
    direction: '|', // no IntelliSense at | (works with createStyles)
    direction: | // IntelliSense works at |
  }
}))

@ypresto通过“杀死它”,您的意思是“使其以与createStyles相同的方式工作”吗?

把它放在任何地方是一种拖累,但没有比把createStyles放在任何地方更多的拖累。

@amacleay我的意思是kills IntelliSense祈祷:。

对不起,我错过了你的评论。 我会试一试。

我不知道为什么,但有趣的是,这是 1100 毫秒 → 750 毫秒:

 export const DropArea: React.FC<CardProps & {
   active?: boolean
   description: string
   icon?: React.ReactNode
-}> = ({ active, description, icon, children, ...props }) => {
+}> = ({ children, ...props }) => {
   const classes = useStyles()
+  const active = false
+  const icon: React.ReactNode = null
+  const description = ''
   return (
     <Card {...props} className={clsx(classes.root)} variant="outlined">

从 FC 中删除CardProps &几乎是相同的结果。 也许是因为 CardProps 扩展了 PaperProps,它扩展了大的 HTMLAttributes。

更新和重要提示:事实证明,用HTMLAttributes<HTMLDivElement>替换 CardProps 也可以减少时间(未测量)。

最后找到了最大的一个,750ms → 130ms:

从两个排版中删除style={...}

-<Typography variant="subtitle2" component="div" noWrap style={{ width: '26ch' }}>...</Typography>
+<Typography variant="subtitle2" component="div" noWrap>...</Typography>
-<Typography variant="caption" component="div" noWrap style={{ width: '20ch' }}>...</Typography>
+<Typography variant="caption" component="div" noWrap>...</Typography>

但为什么? 将相同的样式添加到<div>不会影响性能。 也许OverridableComponent太复杂了..?

(我使用的是 TypeScript 3.8.3, @material-ui/core 4.9.1)

AFAIK Material-UI 处理组件本地样式的方式与 React 处理 HTML 元素的方式不同。

@embeddedt在类型级别,它解析为React.CSSProperties ,与 div 的样式属性相同。

@ypresto我站纠正。 对不起。

大家好,不确定是否值得为此开一个新问题,所以我会在这里发布它,因为它与类型正确性/性能有关。 让我知道我是否应该打开一个问题。
按照文档添加自定义字体时,我最终
Type 'string' is not assignable to type 'FontFaceFontDisplayProperty'

这很奇怪,因为csstype 2.6.9 类型似乎有效,其他属性也可以(使用 MUI 4.9.5)。

const sourceSansPro = {
  fontFamily: "'Source Sans Pro'",
  fontStyle: "normal",
  fontDisplay: "swap", // won't work
  fontWeight: 400,
  src: `
    url('/static/fonts/Source_Sans_Pro/SourceSansPro-Regular.ttf') format("truetype")
  `
};

主题属性:

  overrides: {
    MuiCssBaseline: {
      "@global": {
        "@font-face": [sourceSansPro]
      }
    }

类型是type FontFaceFontDisplayProperty = "auto" | "block" | "fallback" | "optional" | "swap";

@eric-burel 这是打字稿自动类型扩展的问题。 尝试

- fontDisplay: "swap", // won't work
+ fontDisplay: "swap" as "swap",

谢谢,它有效,我学到了一个新概念“类型扩展”:) 例如, fontStyle不受影响,这很奇怪,它不是唯一定义为枚举的 CSS 属性,但我第一次遇到这个.

编辑:好吧,我不好,它有据可查: https: //material-ui.com/guides/typescript/#using -createstyles-to-defeat-type-widening

最后找到了最大的一个,750ms → 130ms:

从两个排版中删除style={...}

-<Typography variant="subtitle2" component="div" noWrap style={{ width: '26ch' }}>...</Typography>
+<Typography variant="subtitle2" component="div" noWrap>...</Typography>
-<Typography variant="caption" component="div" noWrap style={{ width: '20ch' }}>...</Typography>
+<Typography variant="caption" component="div" noWrap>...</Typography>

但为什么? 将相同的样式添加到<div>不会影响性能。 也许OverridableComponent太复杂了..?

(我使用的是 TypeScript 3.8.3, @material-ui/core 4.9.1)

您是否发现这会影响构建时间,或者仅影响智能感知有用的时间? 我遇到了构建问题(内存不足),我们的一些 TS 代码在组件上设置了大量的style={someStyle} 。 想知道这是否是我们问题的一部分。

@yatrix7 ,一般来说,我希望这些较长的检查时间会影响构建和编辑器的响应时间。

我现在有人在研究这个吗? 我知道在以前的版本升级中,在打字稿类型检查时间方面有一些改进。 但是,它仍然很慢。
不介意自己调查一下。

不介意自己调查一下。

那太棒了我们目前不知道可供我们处理的可操作项目。 因此,任何指向瓶颈的指针将不胜感激。

现在添加了一些基准测试,以帮助调查: https :

@FabianKielmann在 TS 端,我一直在研究性能调查工具,我希望这些工具很快就会成熟到适用于 material-ui。

如果你有时间花在这上面,你也可以尝试像https://github.com/microsoft/TypeScript/issues/38583这样的东西

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

ryanflorence picture ryanflorence  ·  3评论

ghost picture ghost  ·  3评论

anthony-dandrea picture anthony-dandrea  ·  3评论

FranBran picture FranBran  ·  3评论

mb-copart picture mb-copart  ·  3评论