记一次TS性能问题排查

1,027 阅读2分钟

现象

在某个node项目中,其ts的语法检查速度过慢,改完变量类型后需要几秒钟的时间才能给到反馈

问题排查

环境

版本信息
-----------------
系统: macOS Big Sur v11.5.2
tsc: v4.5.2
node: v14.17.0

使用ts性能分析工具 Performance Tracing 找出 hot spot.

step1. 执行tsc生成tace文件,可以观察到如下的错误信息

$tsc --generateTrace ./trace

app/model/demo.ts:30:17 - error TS2321: Excessive stack depth comparing types 'Model<?, TQueryHelpers, TMethods>' and 'Model<?, TQueryHelpers, TMethods>'.
30   const model = db.model<Demo>('Demo', DemoSchema);

step2. 在浏览器输入 about://~~~~tracing~~~~ (或者打开浏览器控制面板的Performance - 推荐用这种方式),上传trace文件夹下的trace.json文件

image.png

可以看出,TS在处理app/model/demo.ts 文件用时长达2s+,其代码如下:

import { Mongoose } from 'mongoose';

interface Demo {
  apiId: string;
  accountId: string;
}
 
export default (mongoose: Mongoose.Mongoose, db: Mongoose.Connection) => {
  const { Schema } = mongoose;
  const DemoSchema  = new Schema<Demo>({
    apiId: String,
    accountId: String
  })

  const model = db.model<Demo>('Demo', DecmoSchema);
  return model;
}

这个问题的表面原因是由于TS做类型推断出陷入了无限循环,github上有相关的issue#46989

解决方案

  1. 降级到4.4.3
  1. 对model手动添加类型
export default (mongoose: Mongoose.Mongoose, db: Mongoose.Connection) => {

  - const model = db.model<Demo>('Demo', DemoSchema);
  + const model: Mongoose.Model<Demo> = db.model<Demo>('Demo', DemoSchema);
  
}
  1. 安装vscode插件 JavaScript and TypeScript Nightly extension,提供了最新版的typescript来替代vscode内置的typescript版本(无需调整代码)

Deep(WIP)

debug下ts陷入嵌套的原因

Example : github.com/microsoft/T…

Typescript更新

Typescript在v4.5版本中发布了Feature: Tail-Recurison Elimination on Conditional Types

大概的意思是说,之前的版本中在检查到可能是无限递归的情况时会直接报错,这个版本会消除某些情况下的尾递归来避免这种问题。

这里涉及到的概念

其中类型重载也是一种条件类型,Model.model这个就是类型重载

model<T>(name: string, schema?: Schema<T>, collection?: string): Model<T>;

model<T, U extends Model<T, TQueryHelpers, any>, TQueryHelpers = {}>(
  name: string,
  schema?: Schema<T, U, TQueryHelpers>,
  collection?: string,
  skipInit?: boolean
): U;
  • 尾递归:一个函数返回该函数本身的调用值的递归情况

阅读文档

  1. Typescript性能优化指南 github.com/microsoft/T…