正如@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) 这些包本身是递归的还是只有一个附加层? 也就是说,你是从width
到foo.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
对于它提供的好处来说太贵了。 但是,我很可能不完全了解这些好处,因此了解更多信息会有所帮助。
我们能否共同努力在准确性和性能之间找到正确的平衡点? (注意:“只是让编译器更快”显然是一个可行的策略,但我想在我们优化它们之前将类型放到一个好的位置。)谢谢!
我不熟悉 material-ui 类型,但尝试回答这些问题。
':after': {
content: 'x',
[theme.breakpoints.up('lg')]: {
content: 'close',
},
}
},
}
});
```
b) I do not understand why `BaseCSSProperties[keyof BaseCSSProperties]` is needed there
(props: Props) => CreateCSSProperties<Props>
是不需要的,我们在我们的 material-ui 类型版本中排除了这种类型,并没有发生任何不好的事情。可能值得看看 3.9.3 版本中类型的实现,因为在这个版本中,类型检查足够快,打字也很好。
首先,我要感谢您伸出手来调查此事。 让某人对类型的哪些部分慢或慢进行基准测试是非常有帮助的。
- 我是否正确地假设每个众所周知的 CSS 属性都有一个名称和类型是非常有价值的,而且我们不能放弃?
在这里不可能做到不偏不倚。 尽管着眼于更广泛的生态系统,但我认为我们不能放弃它。 Chrome devtools 有这个功能,react 自己用CSSProperties
等输入style
道具。我看不到自己从 IDE 切换到浏览器并检查它是文本装饰还是字体装饰或文本转换。
- [...]
这些包本身是递归的还是只有一个附加层?
我需要检查我们正在使用的 CSS-in-JS 解决方案。 从技术上讲,CSS 中的媒体查询可以是递归的。 我愿意减少这种递归性,看看我们是否会收到报告。 技术上嵌套的媒体查询可以使用and
运算符进行扁平化。 不过,我们应该将其限制为两个级别:一个用于媒体查询,另一个用于伪选择器。 这仍应进行类型检查 IMO:
const styles = {
root: {
'<strong i="18">@media</strong> (max-width: 12cm)': {
':hover': {}
}
}
}
这是你看到自己在写@oliviertassinari 的东西吗?
- [...]
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 类型(见StylesRequireProps
和StylesHook
。
简而言之:我们避免编写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 时,它会非常混乱/令人沮丧。 尤其是因为大多数造型无论如何都不是基于道具。
似乎大部分时间类型检查器都在忙于样式解决方案? 我会期望我们的组件的调用签名,即大部分时间可能需要什么道具。
我可以抓取更多存储库以专门查看withStyles
或makeStyles
。 到目前为止,我只看过道具的使用。
这是你看到自己在写@oliviertassinari 的东西吗?
@eps1lon我们在代码库中出现了几次这种嵌套(例如<strong i="8">@media</strong> (hover: none)
)。 但是对于核心组件来说不是很频繁。 我想这是同一个用户空间。 这绝对是权衡的一部分。
@beholderrk
BaseCSSProperties[keyof BaseCSSProperties]
- 那么每个属性都有一个兼容的类型。 例如,假设您在 CSS 中可以拥有的唯一属性是name: string
和width: number
。 指定适用于这两个属性的索引签名的一种方法是说每个属性都是string | number
。 这不是很好 - name
永远不会是number
并且width
永远不会是string
- 但它有效。 真正的问题是您想要的东西实际上无法表达(至少,就我们已经能够确定的而言 - 可能有一个“聪明的”黑客可以做到这一点)。 您实际上想说您的类型包含name: string
、 width: number
或x: CSSProperties
,其中x
不是name
或width
- 这是缺少的“除此之外的任何东西”。 我希望这更清楚一点。已知良好的基线将非常有帮助。 你碰巧有链接吗?
编辑:找到了。
@eps1lon 很高兴参与对话。 快速、正确的类型对每个人都有好处。 😄
关于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 typescript
用tslint
和dtslint
的$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: true
和noEmit: 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.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这样的东西
最有用的评论
我今天开始将 Material UI (
4.9.4
) 添加到我的项目中,而且速度下降真的非常严重,我认为我什至无法在我的项目中使用它。 刚刚添加了一个简单的<Slider/>
组件,使用withStyles()
自定义。我们正在谈论从我的 IDE 中的即时 TypeScript 反馈到有时感觉像 5-10 秒(对于我现在甚至不与 Material UI 交互的部分代码 - 它只是使用的文件中的 TypeScript 完全减慢组件)。 这些类型肯定有明显的错误(或者是的,过于复杂),似乎@amcasey正在做一些很好的调查 - 我希望你能深入了解它!
试图找到一种方法,我至少可以暂时排除
@material-ui
所有 TypeScript 内容(基本上使整个模块any
) - 但 TypeScript 似乎并没有让这变得足够容易。