[{"data":1,"prerenderedAt":295},["ShallowReactive",2],{"content:\u002Fposts\u002F2025\u002Ftypescript-performance":3,"surround:\u002Fposts\u002F2025\u002Ftypescript-performance":284},{"id":4,"title":5,"body":6,"canonical":19,"categories":261,"date":263,"description":264,"draft":265,"extension":266,"image":267,"meta":268,"navigation":269,"path":270,"permalink":271,"readingTime":272,"recommend":271,"references":271,"seo":277,"sitemap":278,"stem":279,"tags":280,"type":271,"updated":263,"__hash__":283},"content\u002Fposts\u002F2025\u002Ftypescript-performance.md","【翻译】编写易于编译的TypeScript代码",{"type":7,"value":8,"toc":250},"minimark",[9,24,27,30,34,37,42,45,56,59,62,73,79,82,85,91,98,167,170,173,179,186,192,215,218,221,227,241,244],[10,11,12],"blockquote",{},[13,14,15,16,23],"p",{},"原文地址：",[17,18,22],"a",{"href":19,"rel":20},"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002FTypeScript\u002Fwiki\u002FPerformance",[21],"nofollow","Performance","，本文只摘录《编写易于编译的代码》一部分。",[25,26],"hr",{},[13,28,29],{},"有简单的方法可以配置 TypeScript，以确保更快的编译和编辑体验。越早采用这些实践，效果越好。除了最佳实践之外，还有一些常见的技巧用于调查缓慢的编译\u002F编辑体验，一些常见的修复方法，以及一些常见的方法，帮助 TypeScript 团队作为最后手段调查问题。",[31,32,33],"h2",{"id":33},"编写易于编译的代码",[13,35,36],{},"请注意，以下并非一套完美的规则。根据您的代码库，每条规则都可能存在例外情况。",[38,39,41],"h3",{"id":40},"优先使用-interface-而非交叉类型","优先使用 interface 而非交叉类型",[13,43,44],{},"很多时候，一个简单的对象类型别名与 interface 表现得非常相似。",[46,47,53],"pre",{"className":48,"code":50,"language":51,"meta":52},[49],"language-ts","interface Foo { prop: string }\n\ntype Bar = { prop: string }\n","ts","",[54,55,50],"code",{"__ignoreMap":52},[13,57,58],{},"然而，一旦您需要组合两个或多个类型，您可以选择通过 interface 扩展这些类型，或者在类型别名中使它们相交，这时差异就开始变得重要了。",[13,60,61],{},"interface 创建单一的扁平对象类型，用于检测属性冲突，而解决这些冲突通常至关重要！另一方面，交集只是递归地合并属性，在某些情况下甚至不会产生 never 结果。interface 的显示效果也始终更佳，而指向交集的类型别名无法在其他交集的部分内容中显示。此外，interface 之间的类型关系会被缓存，而交集类型本身则会被缓存。最后一个值得注意的区别是，在检查目标交集类型时，会先检查每个组成部分，然后再检查“有效”\u002F“扁平化”类型。",[13,63,64,65,68,69,72],{},"因此，建议使用 ",[54,66,67],{"code":67},"interface"," s\u002F ",[54,70,71],{"code":71},"extends"," 扩展类型，而不是创建交叉类型。",[46,74,77],{"className":75,"code":76,"language":51,"meta":52},[49],"type Foo = Bar & Baz & { \u002F\u002F [!code --]\n    someProp: string \u002F\u002F [!code --]\n} \u002F\u002F [!code --]\ninterface Foo extends Bar, Baz { \u002F\u002F [!code ++]\n    someProp: string \u002F\u002F [!code ++]\n} \u002F\u002F [!code ++]\n",[54,78,76],{"__ignoreMap":52},[38,80,81],{"id":81},"使用类型注解",[13,83,84],{},"添加类型注解，尤其是返回类型注解，可以为编译器节省大量工作。部分原因是命名类型通常比匿名类型（编译器可能会推断）更简洁，从而减少了读取和写入声明文件的时间（例如，在增量构建中）。类型推断非常方便，因此没有必要普遍启用类型注解——但是，如果您发现代码中存在性能瓶颈，尝试使用类型注解可能很有用。",[46,86,89],{"className":87,"code":88,"language":51,"meta":52},[49],"import { otherFunc } from \"other\"; \u002F\u002F [!code --]\nimport { otherFunc, OtherType } from \"other\"; \u002F\u002F [!code ++]\n\nexport function func() { \u002F\u002F [!code --]\nexport function func(): OtherType { \u002F\u002F [!code ++]\n    return otherFunc();\n}\n",[54,90,88],{"__ignoreMap":52},[13,92,93,94,97],{},"如果你的 --declaration 输出包含类似 ",[54,95,96],{"code":96},"import(\".\u002Fsome\u002Fpath\").SomeType"," 的类型，或者包含源代码中未定义的超大型类型，则可能值得尝试一下。尝试显式地编写一些类型，必要时可以创建一个命名类型。",[99,100,101,104,107,113,116,122,141,164],"folding",{},[13,102,103],{},"对于非常大的计算类型，打印\u002F读取这种类型开销大的原因显而易见；但是，为什么 import() 代码生成开销也大呢？这为什么会是个问题？",[13,105,106],{},"在某些情况下， --declaration emit` 需要引用来自另一个模块的类型。例如，以下文件的声明需要发出……",[46,108,111],{"className":109,"code":110,"language":51,"meta":52},[49],"\u002F\u002F foo.ts\nexport interface Result {\n    headers: any;\n    body: string;\n}\n\nexport async function makeRequest(): Promise\u003CResult> {\n    throw new Error(\"unimplemented\");\n}\n\n\u002F\u002F bar.ts\nimport { makeRequest } from \".\u002Ffoo\";\n\nexport function doStuff() {\n    return makeRequest();\n}\n",[54,112,110],{"__ignoreMap":52},[13,114,115],{},"将生成以下 .d.ts 文件：",[46,117,120],{"className":118,"code":119,"language":51,"meta":52},[49],"\u002F\u002F foo.d.ts\nexport interface Result {\n    headers: any;\n    body: string;\n}\nexport declare function makeRequest(): Promise\u003CResult>;\n\n\u002F\u002F bar.d.ts\nexport declare function doStuff(): Promise\u003Cimport(\".\u002Ffoo\").Result>;\n",[54,121,119],{"__ignoreMap":52},[13,123,124,125,128,129,132,133,136,137,140],{},"注意导入语句 ",[54,126,127],{"code":127},"import(\".\u002Ffoo\").Result"," 需要生成代码，以便在 ",[54,130,131],{"code":131},"bar.ts"," 的声明输出中引用 ",[54,134,135],{"code":135},"foo.ts"," 中名为 ",[54,138,139],{"code":139},"Result"," 类型。这涉及：",[142,143,144,148,155,158,161],"ol",{},[145,146,147],"li",{},"确定该类型是否可以通过本地名称访问。",[145,149,150,151,154],{},"查找类型 type 是否可通过 ",[54,152,153],{"code":153},"import(...)"," 访问。",[145,156,157],{},"计算导入该文件的最合理路径。",[145,159,160],{},"生成新节点以表示该类型引用。",[145,162,163],{},"打印这些类型引用节点。",[13,165,166],{},"对于一个非常大的项目，每个模块中可能会反复出现这种情况。",[38,168,169],{"id":169},"优先使用基本类型而非联合类型",[13,171,172],{},"联合类型非常棒——它们可以让你表达一个类型的可能值范围。",[46,174,177],{"className":175,"code":176,"language":51,"meta":52},[49],"interface WeekdaySchedule {\n  day: \"Monday\" | \"Tuesday\" | \"Wednesday\" | \"Thursday\" | \"Friday\";\n  wake: Time;\n  startWork: Time;\n  endWork: Time;\n  sleep: Time;\n}\n\ninterface WeekendSchedule {\n  day: \"Saturday\" | \"Sunday\";\n  wake: Time;\n  familyMeal: Time;\n  sleep: Time;\n}\n\ndeclare function printSchedule(schedule: WeekdaySchedule | WeekendSchedule);\n",[54,178,176],{"__ignoreMap":52},[13,180,181,182,185],{},"然而，它们也会带来一些代价。每次向 ",[54,183,184],{"code":184},"printSchedule"," 传递参数时，都必须将其与联合体中的每个元素进行比较。对于包含两个元素的联合体来说，这很简单也很省事。但是，如果联合体包含十几个元素，就会严重影响编译速度。例如，要从联合体中消除冗余成员，必须对元素进行两两比较，这相当于二次方复杂度。当对大型联合体进行交集运算时，可能会出现这种检查，因为对每个联合体成员进行交集运算会导致生成非常庞大的类型，而这些类型随后需要进行缩减。避免这种情况的一种方法是使用子类型，而不是联合体。",[46,187,190],{"className":188,"code":189,"language":51,"meta":52},[49],"interface Schedule {\n  day: \"Monday\" | \"Tuesday\" | \"Wednesday\" | \"Thursday\" | \"Friday\" | \"Saturday\" | \"Sunday\";\n  wake: Time;\n  sleep: Time;\n}\n\ninterface WeekdaySchedule extends Schedule {\n  day: \"Monday\" | \"Tuesday\" | \"Wednesday\" | \"Thursday\" | \"Friday\";\n  startWork: Time;\n  endWork: Time;\n}\n\ninterface WeekendSchedule extends Schedule {\n  day: \"Saturday\" | \"Sunday\";\n  familyMeal: Time;\n}\n\ndeclare function printSchedule(schedule: Schedule);\n",[54,191,189],{"__ignoreMap":52},[13,193,194,195,198,199,202,203,206,207,211,212,214],{},"更实际的例子可能出现在尝试对所有内置 DOM 元素类型进行建模时。在这种情况下，最好创建一个包含公共成员的基类 ",[54,196,197],{"code":197},"HtmlElement"," ， ",[54,200,201],{"code":201},"DivElement"," 、 ",[54,204,205],{"code":205},"ImgElement"," 等元素都继承自该基类，而不是创建一个像 DivElement | \u002F",[208,209,210],"em",{},"...","\u002F | ImgElement | \u002F",[208,213,210],{},"\u002F",[38,216,217],{"id":217},"给复杂类型命名",[13,219,220],{},"复杂类型可以写在任何允许类型注解的地方。",[46,222,225],{"className":223,"code":224,"language":51,"meta":52},[49],"interface SomeType\u003CT> {\n    foo\u003CU>(x: U):\n        U extends TypeA\u003CT> ? ProcessTypeA\u003CU, T> :\n        U extends TypeB\u003CT> ? ProcessTypeB\u003CU, T> :\n        U extends TypeC\u003CT> ? ProcessTypeC\u003CU, T> :\n        U;\n}\n",[54,226,224],{"__ignoreMap":52},[13,228,229,230,233,234,237,238,240],{},"这很方便，但如今，每次调用 ",[54,231,232],{"code":232},"foo"," 时，TypeScript 都必须重新运行条件类型判断。此外，关联任意两个 ",[54,235,236],{"code":236},"SomeType"," 实例都需要重新关联 ",[54,239,232],{"code":232}," 返回类型的结构。",[13,242,243],{},"如果将此示例中的返回类型提取到类型别名中，编译器可以缓存更多信息：",[46,245,248],{"className":246,"code":247,"language":51,"meta":52},[49],"type FooResult\u003CU, T> =\n    U extends TypeA\u003CT> ? ProcessTypeA\u003CU, T> :\n    U extends TypeB\u003CT> ? ProcessTypeB\u003CU, T> :\n    U extends TypeC\u003CT> ? ProcessTypeC\u003CU, T> :\n    U;\n\ninterface SomeType\u003CT> {\n    foo\u003CU>(x: U): FooResult\u003CU, T>;\n}\n",[54,249,247],{"__ignoreMap":52},{"title":52,"searchDepth":251,"depth":251,"links":252},4,[253],{"id":33,"depth":254,"text":33,"children":255},2,[256,258,259,260],{"id":40,"depth":257,"text":41},3,{"id":81,"depth":257,"text":81},{"id":169,"depth":257,"text":169},{"id":217,"depth":257,"text":217},[262],"译","2025-11-05 18:00:24","来自 TypeScript 官方的 Wiki 文章，介绍了多种提升 TypeScript 性能的实践方法。",false,"md","https:\u002F\u002Fbitmc.uno\u002Fpicgo\u002Ftranslate-typescript-performance.jpg",{},true,"\u002Fposts\u002F2025\u002Ftypescript-performance",null,{"text":273,"minutes":274,"time":275,"words":276},"8 min read",8,480000,1600,{"title":5,"description":264},{"loc":270},"posts\u002F2025\u002Ftypescript-performance",[281,282],"TypeScript","performance","DX3wtIYVriL4gO6WRcLY2Bw4g_NPWyXP-ARMU1X3W-E",[285,290],{"title":286,"path":287,"stem":288,"date":289,"type":271,"children":-1},"或许你应该看看 shadcn-vue","\u002Fposts\u002F2025\u002Fyou-should-use-shadcn-vue","posts\u002F2025\u002Fyou-should-use-shadcn-vue","2025-10-07 09:56:05",{"title":291,"path":292,"stem":293,"date":294,"type":271,"children":-1},"实用包推荐：ua-parser-js","\u002Fposts\u002F2025\u002Fpackage-recommend-ua-parser-js","posts\u002F2025\u002Fpackage-recommend-ua-parser-js","2025-12-02 11:22:26",1789642588446]