原文:https://github.com/microsoft/...
豆皮粉儿们,又又又见面了,明天这一期,由字节跳动数据平台的“StoneyAllen
”,给大家翻译一篇文章“typescript性能”。在2020年倒计时最初几天我要祝大家新年快乐~,打工人,打工魂~。上面就开始仔细阅读吧!
翻译者:StoneyAllen
有些简略的Typescript配置,能够让你取得更快的编译和编辑体验,这些办法越早把握越好。上面列举了除了最佳实际以外,还有一些用于考察迟缓的编译/编辑体验的罕用技术,以及一些作为最初伎俩来帮忙TypeScript团队考察问题的罕用办法。
编写易编译代码
优先应用接口而不是穿插类型
很多时候,简略对象类型的类型别名与接口的作用十分类似
然而,只有你须要定义两个及以上的类型,你就能够选用接口来扩大这些类型,或者在类型别名中对它们相交,这时差别就变得显著了。
因为接口定义的是繁多立体对象类型,能够检测属性是否抵触,解决这些抵触是十分必要的。另一方面,穿插类型只是递归的合并属性,有些状况下会产生never。接口则体现的一贯很好,而穿插类型定义的类型别名不能显示在其余的穿插类型上。接口之间的类型关系也会被缓存,而不是整个穿插类型。最初值得注意的区别是,如果是穿插类型,会在查看“无效” /“展平”类型之前查看所有属性。
因而,倡议在创立穿插类型时应用带有接口/扩大的扩大类型。
应用类型正文
增加类型正文,尤其是返回类型,能够节俭编译器的大量工作。这是因为命名类型比匿名类型更简洁(编译器更喜爱),这缩小了大量的读写申明文件的工夫。尽管类型推导是十分不便的,没有必要到处这么做。然而,如果您晓得了代码的慢速局部,可能会很有用。
优先应用根底类型而不是联结类型
联结类型十分好用--它能够让你表白一种类型的可能值范畴。
然而他们也带来了肯定开销。每次将参数传递给 printSchedule
时,须要比拟联结类型里的每个元素。对于一个由两个元素组成的联结类型来说,这是微不足道的。然而,如果你的联结类型有很多元素,这将引起编译速度的问题。例如,从联结类型中淘汰多余的局部,元素须要成对的去比拟,工作量是呈二次递增的。当大量联结类型穿插一起时产生这种查看,会在每个联结类型上相交导致大量的类型,须要缩小这种状况产生。防止这种状况的一种办法是应用子类型,而不是联结类型。
一个更事实的例子是,定义每种内置DOM元素的类型时。这种状况下,更优雅的形式是创立一个蕴含所有元素的 HtmlElement
根底类型,其中包含 DivElement
、 ImgElement
等。应用继承而不是创立一个无穷多的联结类型 DivElement | /*...*/ | ImgElement | /*...*/
。
应用我的项目援用
应用TypeScript构建内容较多的代码时,将代码库组织成几个独立的我的项目会很有用。每个我的项目都有本人的 tsconfig.json
,可能它会对其余我的项目有依赖性。这有益于防止在一次编译中导入太多文件,也使某些代码库布局策略更容易地放在一起。
有一些十分根本的办法将一个代码库分解成多个我的项目。举个例子,一个程序代码,一部分用作客户端,一部分用作服务端,另一部分被其它两个共享
测试也能够合成到本人的我的项目中
一个常见的问题是 "一个我的项目应该有多大?"。这很像问 "一个函数应该有多大?"或 "一个类应该有多大?",在很大水平上,这归纳于教训。人们相熟的一种宰割JS/TS代码的办法是应用文件夹。作为一种启发式的办法,如果它们关联性足够大,能够放在同一个文件夹中,那么它们就属于同一个我的项目。除此之外,要避免出现极大或极小规模的我的项目。如果一个我的项目比其余所有我的项目加起来都要大,那就是一个正告信号。同样,最好防止有几十个单文件我的项目,因为也会减少开销。
你能够在这里浏览更多对于我的项目参考资料
配置tsconfig.json或jsconfig.json
TypeScript
和JavaScript
用户能够用tsconfig.json
文件任意配置编译形式。JavaScript
用户也能够应用jsconfig.json
文件配置本人的编辑体验。
指定文件
你应该始终确保你的配置文件没有蕴含太多文件
在 tsconfig.json
中,有两种形式能够指定我的项目中的文件
- files列表
- include、exclude列表
两者的次要区别是,files
冀望失去一个源文件的文件门路列表,而include/exclude
应用通配符模式对文件进行匹配
尽管指定文件能够让TypeScript
间接疾速地加载文件,但如果你的我的项目中有很多文件,而不只是几个顶层的入口,那就会很麻烦。此外,很容易遗记增加新文件到tsconfig.json
中,这意味着你可能最终会失去奇怪的编辑器行为,这些新文件被谬误地剖析,这些都很辣手。
include/exclude
有助于防止指定这些文件,但代价是:必须通过include
蕴含的目录来发现文件。当运行大量的文件夹时,这可能会减慢编译速度。此外,有时编译会蕴含很多不必要的.d.ts
文件和测试文件,这会减少编译工夫和内存开销。最初,尽管exclude
有一些正当的默认值,但某些配置比方mono-repos
,意味着像node_modules
这样的 "重 "文件夹依然能够最终被蕴含。
对于最佳做法,咱们倡议如下:
- 在您的我的项目中只指定输出文件夹(即您想将其源代码蕴含在编译/剖析中的文件夹)
- 不要把其余我的项目的源文件混在同一个文件夹里
- 如果把测试和其余源文件放在同一个文件夹里,请给它们取一个不同的名字,这样就能够很容易地把它们排除在外
- 防止在源目录中呈现大的构建工件和依赖文件夹,如
node_modules
留神:如果没有排除列表,默认状况下node_modules是被排除的;一旦增加了node_modules,就必须明确地将node_modules增加到列表中。
上面是一个正当的tsconfig.json
,用来演示这个操作
管制蕴含的@types
默认状况下,TypeScript
会主动蕴含每一个在node_modules
文件夹中找到的@types
包,不论你是否导入它。这是为了在应用Node.js、Jasmine、Mocha、Chai等工具/包时,使某些货色 "可能工作",因为这些工具/包没有被导入--它们只是被加载到全局环境中
有时这种逻辑在编译和编辑场景下都会拖慢程序的构建工夫,甚至会造成多个全局包的申明抵触的问题,造成相似于如下问题
在不须要全局包的状况下,修复办法很简略,只有在 tsconfig.json/jsconfig.json
中为 "type "选项指定一个空字段即可。
如果您依然须要一些全局包,请将它们增加到类型字段中
增量我的项目输入
--incremental
标记容许TypeScript将上次编译的状态保留到一个 .tsbuildinfo
文件中。这个文件用来计算上次运行后可能被从新查看/从新输入的最小文件集,就像TypeScript的--watch
模式一样。
当对我的项目援用应用复合标记时,默认状况下会启用增量编译,但这样也能带来同样的速度晋升。
跳过 .d.ts 查看
默认状况下,TypeScript会对一个我的项目中的所有.d.ts
文件进行全面查看,以发现问题或不统一的中央;然而,这查看通常是不必要的。大多数时候,.d.ts
文件都是已知如何工作的--类型之间互相扩大的形式曾经被验证过一次,重要的申明还是会被查看。
TypeScript提供了一个选项,应用skipDefaultLibCheck
标记来跳过.d.ts
文件的类型查看(例如lib.d.ts
)
另外,你也能够启用 skipLibCheck
标记来跳过编译中的所有 .d.ts
文件
这两个选项通常会暗藏.d.ts
文件中的谬误配置和抵触,所以只倡议在疾速构建场景中应用它们。
应用更快的差别查看
狗的列表是动物的列表吗?也就是说,List<Dog>
是否能够调配给List<Animals>
?寻找答案的间接办法是一一成员进行类型构造比拟。可怜的是,这可能带来低廉的性能开销。然而,如果咱们对List<T>
有足够的理解,咱们能够将这个可调配性查看简化为确定Dog,是否能够调配给Animal(即不思考List<T>
的每个成员)。特地是,当咱们须要晓得类型参数T的差异。编译器只有在启用strictFunctionTypes
标记的状况下,能力充分利用这种潜在的减速劣势(否则,它就会应用较慢的,但更宽松的构造查看)。因而,咱们倡议应用 --strictFunctionTypes
来构建(默认在 --strict
下启用)
配置其余构建工具
TypeScript编译常常与其余构建工具一起执行--特地是在编写可能波及捆绑程序的Web应用程序时。尽管咱们只能对一些构建工具提出倡议,但现实状况下,这些技术能够被遍及。
确保除了浏览本节外,你还浏览了对于你所抉择的构建工具的性能--例如:
- ts-loader的Faster Builds局部
- awesome-typescript-loader的性能问题局部
并行类型查看
类型查看通常须要从其余文件中获取信息,与转换/输入代码等其余步骤相比,类型查看可能绝对低廉。因为类型查看可能会破费更多的工夫,它可能会影响到外部的开发循环--换句话说,你可能会经验更长的编辑/编译/运行周期,这可能会令你头疼。
出于这个起因,一些构建工具能够在一个独自的过程中运行类型查看,而不会阻塞输入。尽管这意味着在TypeScript构建而产生错误报告之前曾经有有效的代码运行,通常会先在编辑器中看到谬误,而不会被长时间地阻止运行工作代码
一个理论的例子是Webpack的fork-ts-checker-webpack-plugin
插件,或者awesome-typescript-loader
有时也会这样做。
隔离文件输入
默认状况下,TypeScript输入须要的语义信息可能不是本地文件。这是为了了解如何输入像 const enums
和 namespaces
这样的性能。然而须要查看其余文件来生成某个文件,这会使输入速度变慢。
对须要非本地信息的性能需要是比拟少见的--惯例枚举能够用来代替const
枚举,模块能够用来代替命名空间。鉴于此,TypeScript提供了isolatedModules
标记,以便在由非本地信息驱动的性能上报错。启用 isolatedModules
意味着你的代码库对于应用 TypeScript APIs
(如 transpileModule
)或代替编译器(如 Babel
)的工具是平安的。
举个例子,上面的代码在运行时无奈失常应用独立的文件转换,因为const enum
值被冀望内联;侥幸的是, isolatedModules
会在晚期通知咱们这一点
记住:isolatedModules不会主动让代码生成速度更快--它只是通知你,你行将应用一个可能不被反对的性能。你要的是独立模块在不同的构建工具和API中的输入
能够通过应用以下工具来影响独立文件的输入
- ts-loader提供了一个transpileOnly标记,通过应用transpileModule来执行独立文件输入
- awesome-typescript-loader提供了一个transpileOnly标记,通过应用transpileModule来执行独立文件输入
- TypeScript能够间接应用transpileModule API
- awesome-typescript-loader提供了useBabel标记
- babel-loader以独自的形式编译文件(但不提供类型查看)
- gulp-typescript 启用 isolatedModules 时,能够实现独立文件输入
- rollup-plugin-typescript只执行独立文件编译
- ts-jest能够应用( isolatedModules标记设为true )isolatedModules为true
- ts-node 能够检测 tsconfig.json 的 "ts-node "字段中的 "transpileOnly "选项,也有一个 --transpile-only 标记。
考察问题
有肯定的办法能够失去可能出问题的提醒
禁用编辑器插件
编辑器的体验受到插件的影响。尝试禁用插件(尤其是JavaScript/TypeScript相干的插件),看看是否能解决性能和响应速度方面的问题。
某些编辑器也有本人的性能故障排除指南,所以能够思考浏览一下。例如,Visual Studio Code
也有本人的性能问题介绍。
诊断扩大
你能够用--extendedDiagnostics
来运行TypeScript,以取得编译器破费工夫的打印日志。
请留神,总工夫不是后面所有工夫的总和,因为有一些重叠,有些工作是没有掂量工具的。
对于大多数用户来说,最相干的信息是:
思考到这些投入,你可能会想问一些问题:
- 文件数/代码行数是否与您我的项目中的文件数大抵统一?如果不合乎,请尝试运行
--listFiles
- 程序工夫或I/O读取工夫是否相当高?请确保你的include/exclude配置正确
其余工夫看起来不对劲吗?你可能想提出一个问题。你能够做以下事件来帮忙诊断
- 如果打印工夫较高,则应用
emitDeclarationOnly
运行 - 浏览对于报告编译器性能问题的阐明
- 如果打印工夫较高,则应用
显示配置
当运行 tsc 时,并不能显著地看到编译的内容设置,特地是思考到 tsconfig.jsons
能够扩大其余配置文件。showConfig
能够解释 tsc 将为一个调用计算着什么。
追踪分辨率
运行 traceResolution
能够有助于解释,一个文件为什么被蕴含在编译中。输入有点繁琐,所以你可能想把输入重定向到一个文件。
如果你发现了一个不应该存在的文件,你可能须要批改你的tsconfig.json中的include/exclude列表,或者,你可能须要调整其余设置,比方type、typeRoots或paths。
独立运行tsc
很多时候,用户在应用第三方构建工具(如Gulp、Rollup、Webpack等)时都会遇到性能迟缓的问题。运行tsc --extendedDiagnostics
,能够发现TypeScript和工具之间的差别,用以阐明内部配置的谬误或效率低下。
一些须要留神的问题:
- tsc和集成了TypeScript的构建工具在构建工夫上有很大的区别吗?
- 如果构建工具提供诊断,那么TypeScript的分辨率和构建工具的分辨率是否有区别?
- 构建工具是否有本人的配置,可能的起因是什么?
- 构建工具是否有可能是TypeScript集成的配置起因?(例如ts-loader的选项?)
降级依赖性
有时TypeScript的类型查看会受到计算密集的.d.ts
文件的影响。这很常见也很可能会产生。降级到一个较新的TypeScript版本(能够更有效率)或一个较新版本的@types包(可能曾经复原了一个回归)通常能够解决这个问题。
常见的问题
一旦你曾经排除了故障,你可能想摸索一些常见问题的修复办法。如果以下解决方案不起作用,可能值得提出问题。
include和exclude配置不当
如上所述,include/exclude选项能够在以下几个方面被滥用
提出问题
如果你的我的项目曾经进行了正确的优化配置,你可能须要提出一个问题。
最好的性能问题报告蕴含容易取得的和最小的问题复制品。换句话说,一个容易通过git克隆的代码库,只蕴含几个文件。它们不须要与构建工具的内部集成--它们能够通过调用tsc或调用TypeScript API的独立代码。不优先思考那些须要简单调用和设置的代码库。
咱们了解这一点却不容易实现--特地是,很难在代码库中隔离问题的源头,而且共享知识产权可能也是一个问题。在某些状况下,如果咱们认为问题影响较大,团队将违心发送一份窃密协定(NDA)。
无论是否能够复制,在提交问题时,依照这些办法,将有助于为您提供性能修复。
报告编译器性能问题
有时,你会在构建工夫以及编辑场景中发现性能问题。在这种状况下,最好关注于TypeScript编译器。
首先,应该应用TypeScript的next版本,以确保你不会碰到那些已解决的问题。
一个编译器的问题可能包含
- 装置的TypeScript版本(例如:npx tsc -v 或 yarn tsc -v)
- TypeScript运行的Node版本(例如:node -v)
- 应用extendedDiagnostics运行的输入(tsc --extendedDiagnostics -p tsconfig.json)
- 现实的状况是,一个我的项目可能展现所遇到的问题
- 分析编译器的输入日志(isolate-*-*-*.log 和*.cpuprofile 文件)
分析编译器
通过应用--trace-ic
标记与--generateCpuProfile
标记,来让TypeScript运行Node.js v10+,这对团队提供诊断后果来说是很重要的:
这里的 ./node_modules/typescript/lib/tsc.js 能够用来替换你的TypeScript编译器的装置版本,而tsconfig.json能够是任何TypeScript配置文件。 profile.cpuprofile是你抉择的输入文件。
这将产生两个文件:
--trace-ic
将输入到 isolate-*-*-*.log 的文件中(例如 isolate-00000176DB2DF130-17676-v8.log)--generateCpuProfile
将以您抉择的名称输入到一个文件中。在下面的例子中,它将是一个名为 profile.cpuprofile 的文件
正告:这些文件可能蕴含你的工作空间的信息,包含文件门路和源代码。这两个文件都能够作为纯文本浏览,您能够在将它们提交为 GitHub 问题之前批改它们。(例如,革除可能裸露外部专用信息的文件门路)。
然而,如果你对在GitHub上公开公布这些有任何顾虑,请通知咱们,能够私下分享细节。
报告编辑绩效问题
编辑性能常常受到很多货色的影响,TypeScript团队惟一能管制的是JavaScript/TypeScript语言服务的性能,以及该语言服务和某些编辑器(即Visual Studio、Visual Studio Code、Visual Studio for Mac和Sublime Text)之间的集成。确保所有第三方插件在编辑器中被敞开,以确定是否有TypeScript自身的问题。
编辑性能问题稍有波及,但同样的想法也实用于:可被克隆的最小重现代码库是现实的,尽管在某些状况下,团队将可能签订NDA来考察和隔离问题。
包含tsc--extendedDiagnostics的输入是很好的上下文,但取一个TSServer日志是最有用的。
收集TSServer日志
在Visual Studio代码中收集TSServer日志
关上你的命令菜单栏,而后抉择
- 进入 "首选项 "关上您的全局设置。关上用户设置
- 入偏好设置,关上本地我的项目。关上工作区设置
- 设置选项 "typecript.tsserver.log":"verbose"
- 重启VS Code,重现问题
- 在VS Code中,运行TypeScript。关上TS服务器日志命令
- 这将关上tsserver.log文件
⚠正告:TSServer日志可能会蕴含你的工作空间的信息,包含文件门路和源代码。如果你对在GitHub上公开公布有任何顾虑,请通知咱们,你能够私下分享细节。