tsc-ts 0.0.4 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (584) hide show
  1. package/README.md +34 -2
  2. package/dist/api/compiler/ast-utilities.d.ts +82 -0
  3. package/dist/api/compiler/ast-utilities.js +462 -0
  4. package/dist/api/compiler/ast.d.ts +2351 -0
  5. package/dist/api/compiler/ast.js +11212 -0
  6. package/dist/api/compiler/astnav.d.ts +37 -0
  7. package/dist/api/compiler/astnav.js +767 -0
  8. package/dist/api/compiler/binder-utilities.d.ts +182 -0
  9. package/dist/api/compiler/binder-utilities.js +1241 -0
  10. package/dist/api/compiler/binder.d.ts +33 -0
  11. package/dist/api/compiler/binder.js +2359 -0
  12. package/dist/api/compiler/character-codes.d.ts +161 -0
  13. package/dist/api/compiler/character-codes.js +160 -0
  14. package/dist/api/compiler/checker-calls.d.ts +46 -0
  15. package/dist/api/compiler/checker-calls.js +1641 -0
  16. package/dist/api/compiler/checker-classes.d.ts +30 -0
  17. package/dist/api/compiler/checker-classes.js +582 -0
  18. package/dist/api/compiler/checker-contextual.d.ts +77 -0
  19. package/dist/api/compiler/checker-contextual.js +1136 -0
  20. package/dist/api/compiler/checker-declaration-order.d.ts +12 -0
  21. package/dist/api/compiler/checker-declaration-order.js +357 -0
  22. package/dist/api/compiler/checker-declarations.d.ts +33 -0
  23. package/dist/api/compiler/checker-declarations.js +888 -0
  24. package/dist/api/compiler/checker-declared-types.d.ts +48 -0
  25. package/dist/api/compiler/checker-declared-types.js +788 -0
  26. package/dist/api/compiler/checker-decorators.d.ts +26 -0
  27. package/dist/api/compiler/checker-decorators.js +562 -0
  28. package/dist/api/compiler/checker-deprecation.d.ts +33 -0
  29. package/dist/api/compiler/checker-deprecation.js +314 -0
  30. package/dist/api/compiler/checker-destructuring.d.ts +34 -0
  31. package/dist/api/compiler/checker-destructuring.js +584 -0
  32. package/dist/api/compiler/checker-elaboration.d.ts +15 -0
  33. package/dist/api/compiler/checker-elaboration.js +291 -0
  34. package/dist/api/compiler/checker-emit-helpers.d.ts +58 -0
  35. package/dist/api/compiler/checker-emit-helpers.js +154 -0
  36. package/dist/api/compiler/checker-emit-resolver.d.ts +75 -0
  37. package/dist/api/compiler/checker-emit-resolver.js +580 -0
  38. package/dist/api/compiler/checker-evaluator.d.ts +27 -0
  39. package/dist/api/compiler/checker-evaluator.js +188 -0
  40. package/dist/api/compiler/checker-expressions.d.ts +67 -0
  41. package/dist/api/compiler/checker-expressions.js +1351 -0
  42. package/dist/api/compiler/checker-features.d.ts +6 -0
  43. package/dist/api/compiler/checker-features.js +354 -0
  44. package/dist/api/compiler/checker-flow.d.ts +86 -0
  45. package/dist/api/compiler/checker-flow.js +169 -0
  46. package/dist/api/compiler/checker-functions.d.ts +43 -0
  47. package/dist/api/compiler/checker-functions.js +1002 -0
  48. package/dist/api/compiler/checker-generated-code.d.ts +25 -0
  49. package/dist/api/compiler/checker-generated-code.js +168 -0
  50. package/dist/api/compiler/checker-globals.d.ts +14 -0
  51. package/dist/api/compiler/checker-globals.js +37 -0
  52. package/dist/api/compiler/checker-grammar.d.ts +35 -0
  53. package/dist/api/compiler/checker-grammar.js +2587 -0
  54. package/dist/api/compiler/checker-heritage.d.ts +28 -0
  55. package/dist/api/compiler/checker-heritage.js +901 -0
  56. package/dist/api/compiler/checker-inference.d.ts +179 -0
  57. package/dist/api/compiler/checker-inference.js +2105 -0
  58. package/dist/api/compiler/checker-iteration.d.ts +115 -0
  59. package/dist/api/compiler/checker-iteration.js +857 -0
  60. package/dist/api/compiler/checker-javascript.d.ts +42 -0
  61. package/dist/api/compiler/checker-javascript.js +442 -0
  62. package/dist/api/compiler/checker-jsdoc.d.ts +30 -0
  63. package/dist/api/compiler/checker-jsdoc.js +320 -0
  64. package/dist/api/compiler/checker-jsx.d.ts +94 -0
  65. package/dist/api/compiler/checker-jsx.js +1433 -0
  66. package/dist/api/compiler/checker-literals.d.ts +6 -0
  67. package/dist/api/compiler/checker-literals.js +43 -0
  68. package/dist/api/compiler/checker-members.d.ts +200 -0
  69. package/dist/api/compiler/checker-members.js +2148 -0
  70. package/dist/api/compiler/checker-modules.d.ts +85 -0
  71. package/dist/api/compiler/checker-modules.js +2141 -0
  72. package/dist/api/compiler/checker-narrowing.d.ts +120 -0
  73. package/dist/api/compiler/checker-narrowing.js +2797 -0
  74. package/dist/api/compiler/checker-object-literals.d.ts +14 -0
  75. package/dist/api/compiler/checker-object-literals.js +483 -0
  76. package/dist/api/compiler/checker-operators.d.ts +33 -0
  77. package/dist/api/compiler/checker-operators.js +1040 -0
  78. package/dist/api/compiler/checker-overloads.d.ts +7 -0
  79. package/dist/api/compiler/checker-overloads.js +271 -0
  80. package/dist/api/compiler/checker-property-access.d.ts +34 -0
  81. package/dist/api/compiler/checker-property-access.js +672 -0
  82. package/dist/api/compiler/checker-services.d.ts +49 -0
  83. package/dist/api/compiler/checker-services.js +995 -0
  84. package/dist/api/compiler/checker-signatures.d.ts +55 -0
  85. package/dist/api/compiler/checker-signatures.js +789 -0
  86. package/dist/api/compiler/checker-source-file.d.ts +27 -0
  87. package/dist/api/compiler/checker-source-file.js +619 -0
  88. package/dist/api/compiler/checker-statements.d.ts +18 -0
  89. package/dist/api/compiler/checker-statements.js +226 -0
  90. package/dist/api/compiler/checker-super.d.ts +13 -0
  91. package/dist/api/compiler/checker-super.js +241 -0
  92. package/dist/api/compiler/checker-symbol-types.d.ts +51 -0
  93. package/dist/api/compiler/checker-symbol-types.js +955 -0
  94. package/dist/api/compiler/checker-symbols.d.ts +181 -0
  95. package/dist/api/compiler/checker-symbols.js +1784 -0
  96. package/dist/api/compiler/checker-type-factory.d.ts +142 -0
  97. package/dist/api/compiler/checker-type-factory.js +2542 -0
  98. package/dist/api/compiler/checker-type-nodes.d.ts +26 -0
  99. package/dist/api/compiler/checker-type-nodes.js +828 -0
  100. package/dist/api/compiler/checker-type-operators.d.ts +109 -0
  101. package/dist/api/compiler/checker-type-operators.js +1842 -0
  102. package/dist/api/compiler/checker-types.d.ts +1093 -0
  103. package/dist/api/compiler/checker-types.js +1874 -0
  104. package/dist/api/compiler/checker-unused.d.ts +19 -0
  105. package/dist/api/compiler/checker-unused.js +524 -0
  106. package/dist/api/compiler/checker-utilities.d.ts +33 -0
  107. package/dist/api/compiler/checker-utilities.js +141 -0
  108. package/dist/api/compiler/checker.d.ts +512 -0
  109. package/dist/api/compiler/checker.js +932 -0
  110. package/dist/api/compiler/command-line.d.ts +32 -0
  111. package/dist/api/compiler/command-line.js +383 -0
  112. package/dist/api/compiler/compile-program.d.ts +118 -0
  113. package/dist/api/compiler/compile-program.js +384 -0
  114. package/dist/api/compiler/diagnostic-locales.d.ts +22 -0
  115. package/dist/api/compiler/diagnostic-locales.js +64 -0
  116. package/dist/api/compiler/diagnostic-messages.d.ts +2166 -0
  117. package/dist/api/compiler/diagnostic-messages.js +184 -0
  118. package/dist/api/compiler/diagnostics.d.ts +161 -0
  119. package/dist/api/compiler/diagnostics.js +784 -0
  120. package/dist/api/compiler/emitter.d.ts +71 -0
  121. package/dist/api/compiler/emitter.js +327 -0
  122. package/dist/api/compiler/file-include.d.ts +144 -0
  123. package/dist/api/compiler/file-include.js +599 -0
  124. package/dist/api/compiler/file-loader.d.ts +290 -0
  125. package/dist/api/compiler/file-loader.js +1323 -0
  126. package/dist/api/compiler/file-system.d.ts +51 -0
  127. package/dist/api/compiler/file-system.js +132 -0
  128. package/dist/api/compiler/flow.d.ts +60 -0
  129. package/dist/api/compiler/flow.js +45 -0
  130. package/dist/api/compiler/instantiation.d.ts +74 -0
  131. package/dist/api/compiler/instantiation.js +835 -0
  132. package/dist/api/compiler/jsdoc.d.ts +75 -0
  133. package/dist/api/compiler/jsdoc.js +1229 -0
  134. package/dist/api/compiler/link-tables.d.ts +105 -0
  135. package/dist/api/compiler/link-tables.js +319 -0
  136. package/dist/api/compiler/locale-data.d.ts +24 -0
  137. package/dist/api/compiler/locale-data.js +183 -0
  138. package/dist/api/compiler/locale.d.ts +4 -0
  139. package/dist/api/compiler/locale.js +317 -0
  140. package/dist/api/compiler/locales/cs-CZ.d.ts +2 -0
  141. package/dist/api/compiler/locales/cs-CZ.js +3 -0
  142. package/dist/api/compiler/locales/de-DE.d.ts +2 -0
  143. package/dist/api/compiler/locales/de-DE.js +3 -0
  144. package/dist/api/compiler/locales/es-ES.d.ts +2 -0
  145. package/dist/api/compiler/locales/es-ES.js +3 -0
  146. package/dist/api/compiler/locales/fr-FR.d.ts +2 -0
  147. package/dist/api/compiler/locales/fr-FR.js +3 -0
  148. package/dist/api/compiler/locales/it-IT.d.ts +2 -0
  149. package/dist/api/compiler/locales/it-IT.js +3 -0
  150. package/dist/api/compiler/locales/ja-JP.d.ts +2 -0
  151. package/dist/api/compiler/locales/ja-JP.js +3 -0
  152. package/dist/api/compiler/locales/ko-KR.d.ts +2 -0
  153. package/dist/api/compiler/locales/ko-KR.js +3 -0
  154. package/dist/api/compiler/locales/pl-PL.d.ts +2 -0
  155. package/dist/api/compiler/locales/pl-PL.js +3 -0
  156. package/dist/api/compiler/locales/pt-BR.d.ts +2 -0
  157. package/dist/api/compiler/locales/pt-BR.js +3 -0
  158. package/dist/api/compiler/locales/ru-RU.d.ts +2 -0
  159. package/dist/api/compiler/locales/ru-RU.js +3 -0
  160. package/dist/api/compiler/locales/tr-TR.d.ts +2 -0
  161. package/dist/api/compiler/locales/tr-TR.js +3 -0
  162. package/dist/api/compiler/locales/zh-CN.d.ts +2 -0
  163. package/dist/api/compiler/locales/zh-CN.js +3 -0
  164. package/dist/api/compiler/locales/zh-TW.d.ts +2 -0
  165. package/dist/api/compiler/locales/zh-TW.js +3 -0
  166. package/dist/api/compiler/module-resolution-types.d.ts +83 -0
  167. package/dist/api/compiler/module-resolution-types.js +176 -0
  168. package/dist/api/compiler/module-resolution.d.ts +71 -0
  169. package/dist/api/compiler/module-resolution.js +1598 -0
  170. package/dist/api/compiler/module-specifiers.d.ts +64 -0
  171. package/dist/api/compiler/module-specifiers.js +1101 -0
  172. package/dist/api/compiler/name-resolver.d.ts +43 -0
  173. package/dist/api/compiler/name-resolver.js +509 -0
  174. package/dist/api/compiler/node-builder-names.d.ts +32 -0
  175. package/dist/api/compiler/node-builder-names.js +854 -0
  176. package/dist/api/compiler/node-builder-pseudo.d.ts +36 -0
  177. package/dist/api/compiler/node-builder-pseudo.js +745 -0
  178. package/dist/api/compiler/node-builder-reuse.d.ts +4 -0
  179. package/dist/api/compiler/node-builder-reuse.js +647 -0
  180. package/dist/api/compiler/node-builder.d.ts +270 -0
  181. package/dist/api/compiler/node-builder.js +2645 -0
  182. package/dist/api/compiler/option-declarations.d.ts +90 -0
  183. package/dist/api/compiler/option-declarations.js +1460 -0
  184. package/dist/api/compiler/options.d.ts +289 -0
  185. package/dist/api/compiler/options.js +1197 -0
  186. package/dist/api/compiler/output-paths.d.ts +42 -0
  187. package/dist/api/compiler/output-paths.js +195 -0
  188. package/dist/api/compiler/package-json.d.ts +175 -0
  189. package/dist/api/compiler/package-json.js +1015 -0
  190. package/dist/api/compiler/parallel-parse.d.ts +221 -0
  191. package/dist/api/compiler/parallel-parse.js +541 -0
  192. package/dist/api/compiler/parser.d.ts +604 -0
  193. package/dist/api/compiler/parser.js +6426 -0
  194. package/dist/api/compiler/path.d.ts +91 -0
  195. package/dist/api/compiler/path.js +705 -0
  196. package/dist/api/compiler/printer/async-helpers.d.ts +22 -0
  197. package/dist/api/compiler/printer/async-helpers.js +91 -0
  198. package/dist/api/compiler/printer/auto-generate.d.ts +13 -0
  199. package/dist/api/compiler/printer/auto-generate.js +20 -0
  200. package/dist/api/compiler/printer/decorator-helpers.d.ts +24 -0
  201. package/dist/api/compiler/printer/decorator-helpers.js +118 -0
  202. package/dist/api/compiler/printer/emit-context.d.ts +157 -0
  203. package/dist/api/compiler/printer/emit-context.js +582 -0
  204. package/dist/api/compiler/printer/emit-flags.d.ts +60 -0
  205. package/dist/api/compiler/printer/emit-flags.js +2 -0
  206. package/dist/api/compiler/printer/factory-base.d.ts +171 -0
  207. package/dist/api/compiler/printer/factory-base.js +1505 -0
  208. package/dist/api/compiler/printer/factory.d.ts +147 -0
  209. package/dist/api/compiler/printer/factory.js +542 -0
  210. package/dist/api/compiler/printer/helpers.d.ts +27 -0
  211. package/dist/api/compiler/printer/helpers.js +164 -0
  212. package/dist/api/compiler/printer/name-generator.d.ts +41 -0
  213. package/dist/api/compiler/printer/name-generator.js +283 -0
  214. package/dist/api/compiler/printer/printer.d.ts +411 -0
  215. package/dist/api/compiler/printer/printer.js +4517 -0
  216. package/dist/api/compiler/printer/text-writer.d.ts +46 -0
  217. package/dist/api/compiler/printer/text-writer.js +172 -0
  218. package/dist/api/compiler/printer/utilities.d.ts +82 -0
  219. package/dist/api/compiler/printer/utilities.js +817 -0
  220. package/dist/api/compiler/program-checker.d.ts +156 -0
  221. package/dist/api/compiler/program-checker.js +529 -0
  222. package/dist/api/compiler/program-utilities.d.ts +52 -0
  223. package/dist/api/compiler/program-utilities.js +365 -0
  224. package/dist/api/compiler/program.d.ts +180 -0
  225. package/dist/api/compiler/program.js +1019 -0
  226. package/dist/api/compiler/pseudo-bigint.d.ts +5 -0
  227. package/dist/api/compiler/pseudo-bigint.js +61 -0
  228. package/dist/api/compiler/regexp-checker.d.ts +38 -0
  229. package/dist/api/compiler/regexp-checker.js +942 -0
  230. package/dist/api/compiler/relations.d.ts +263 -0
  231. package/dist/api/compiler/relations.js +4002 -0
  232. package/dist/api/compiler/reparser.d.ts +48 -0
  233. package/dist/api/compiler/reparser.js +1323 -0
  234. package/dist/api/compiler/scanner.d.ts +256 -0
  235. package/dist/api/compiler/scanner.js +2853 -0
  236. package/dist/api/compiler/side-state.d.ts +16 -0
  237. package/dist/api/compiler/side-state.js +89 -0
  238. package/dist/api/compiler/sourcemap.d.ts +55 -0
  239. package/dist/api/compiler/sourcemap.js +340 -0
  240. package/dist/api/compiler/spelling.d.ts +14 -0
  241. package/dist/api/compiler/spelling.js +128 -0
  242. package/dist/api/compiler/symbol-accessibility.d.ts +57 -0
  243. package/dist/api/compiler/symbol-accessibility.js +991 -0
  244. package/dist/api/compiler/symbol.d.ts +282 -0
  245. package/dist/api/compiler/symbol.js +339 -0
  246. package/dist/api/compiler/symlinks.d.ts +32 -0
  247. package/dist/api/compiler/symlinks.js +114 -0
  248. package/dist/api/compiler/syntax-kind.d.ts +389 -0
  249. package/dist/api/compiler/syntax-kind.js +2 -0
  250. package/dist/api/compiler/timeline.d.ts +9 -0
  251. package/dist/api/compiler/timeline.js +54 -0
  252. package/dist/api/compiler/transformers/alias-references.d.ts +39 -0
  253. package/dist/api/compiler/transformers/alias-references.js +677 -0
  254. package/dist/api/compiler/transformers/async-utilities.d.ts +51 -0
  255. package/dist/api/compiler/transformers/async-utilities.js +260 -0
  256. package/dist/api/compiler/transformers/async.d.ts +53 -0
  257. package/dist/api/compiler/transformers/async.js +645 -0
  258. package/dist/api/compiler/transformers/class-fields.d.ts +206 -0
  259. package/dist/api/compiler/transformers/class-fields.js +2418 -0
  260. package/dist/api/compiler/transformers/class-utilities.d.ts +46 -0
  261. package/dist/api/compiler/transformers/class-utilities.js +261 -0
  262. package/dist/api/compiler/transformers/commonjs-module.d.ts +103 -0
  263. package/dist/api/compiler/transformers/commonjs-module.js +1180 -0
  264. package/dist/api/compiler/transformers/const-enum-inliner.d.ts +11 -0
  265. package/dist/api/compiler/transformers/const-enum-inliner.js +36 -0
  266. package/dist/api/compiler/transformers/declarations-diagnostics.d.ts +52 -0
  267. package/dist/api/compiler/transformers/declarations-diagnostics.js +539 -0
  268. package/dist/api/compiler/transformers/declarations-pseudo.d.ts +160 -0
  269. package/dist/api/compiler/transformers/declarations-pseudo.js +799 -0
  270. package/dist/api/compiler/transformers/declarations-resolver.d.ts +152 -0
  271. package/dist/api/compiler/transformers/declarations-resolver.js +35 -0
  272. package/dist/api/compiler/transformers/declarations-syntactic.d.ts +119 -0
  273. package/dist/api/compiler/transformers/declarations-syntactic.js +1582 -0
  274. package/dist/api/compiler/transformers/declarations-tracker.d.ts +46 -0
  275. package/dist/api/compiler/transformers/declarations-tracker.js +198 -0
  276. package/dist/api/compiler/transformers/declarations.d.ts +175 -0
  277. package/dist/api/compiler/transformers/declarations.js +2381 -0
  278. package/dist/api/compiler/transformers/decorator-metadata.d.ts +54 -0
  279. package/dist/api/compiler/transformers/decorator-metadata.js +554 -0
  280. package/dist/api/compiler/transformers/decorator-utilities.d.ts +38 -0
  281. package/dist/api/compiler/transformers/decorator-utilities.js +238 -0
  282. package/dist/api/compiler/transformers/destructuring.d.ts +25 -0
  283. package/dist/api/compiler/transformers/destructuring.js +626 -0
  284. package/dist/api/compiler/transformers/downlevel.d.ts +6 -0
  285. package/dist/api/compiler/transformers/downlevel.js +45 -0
  286. package/dist/api/compiler/transformers/emit-resolver.d.ts +61 -0
  287. package/dist/api/compiler/transformers/emit-resolver.js +197 -0
  288. package/dist/api/compiler/transformers/es-decorators.d.ts +118 -0
  289. package/dist/api/compiler/transformers/es-decorators.js +1901 -0
  290. package/dist/api/compiler/transformers/exponentiation.d.ts +11 -0
  291. package/dist/api/compiler/transformers/exponentiation.js +76 -0
  292. package/dist/api/compiler/transformers/external-module-info.d.ts +35 -0
  293. package/dist/api/compiler/transformers/external-module-info.js +351 -0
  294. package/dist/api/compiler/transformers/for-await.d.ts +43 -0
  295. package/dist/api/compiler/transformers/for-await.js +469 -0
  296. package/dist/api/compiler/transformers/import-elision.d.ts +16 -0
  297. package/dist/api/compiler/transformers/import-elision.js +124 -0
  298. package/dist/api/compiler/transformers/jsx-entities.d.ts +1 -0
  299. package/dist/api/compiler/transformers/jsx-entities.js +256 -0
  300. package/dist/api/compiler/transformers/jsx.d.ts +71 -0
  301. package/dist/api/compiler/transformers/jsx.js +700 -0
  302. package/dist/api/compiler/transformers/legacy-decorators.d.ts +56 -0
  303. package/dist/api/compiler/transformers/legacy-decorators.js +564 -0
  304. package/dist/api/compiler/transformers/logical-assignment.d.ts +14 -0
  305. package/dist/api/compiler/transformers/logical-assignment.js +62 -0
  306. package/dist/api/compiler/transformers/module-utilities.d.ts +9 -0
  307. package/dist/api/compiler/transformers/module-utilities.js +36 -0
  308. package/dist/api/compiler/transformers/module.d.ts +49 -0
  309. package/dist/api/compiler/transformers/module.js +296 -0
  310. package/dist/api/compiler/transformers/named-evaluation.d.ts +26 -0
  311. package/dist/api/compiler/transformers/named-evaluation.js +266 -0
  312. package/dist/api/compiler/transformers/nullish-coalescing.d.ts +9 -0
  313. package/dist/api/compiler/transformers/nullish-coalescing.js +26 -0
  314. package/dist/api/compiler/transformers/object-rest-spread.d.ts +34 -0
  315. package/dist/api/compiler/transformers/object-rest-spread.js +411 -0
  316. package/dist/api/compiler/transformers/optional-catch.d.ts +9 -0
  317. package/dist/api/compiler/transformers/optional-catch.js +20 -0
  318. package/dist/api/compiler/transformers/optional-chain.d.ts +14 -0
  319. package/dist/api/compiler/transformers/optional-chain.js +188 -0
  320. package/dist/api/compiler/transformers/reference-resolver.d.ts +129 -0
  321. package/dist/api/compiler/transformers/reference-resolver.js +1157 -0
  322. package/dist/api/compiler/transformers/runtime-syntax.d.ts +71 -0
  323. package/dist/api/compiler/transformers/runtime-syntax.js +753 -0
  324. package/dist/api/compiler/transformers/subtree-facts.d.ts +10 -0
  325. package/dist/api/compiler/transformers/subtree-facts.js +205 -0
  326. package/dist/api/compiler/transformers/syntax-facts.d.ts +52 -0
  327. package/dist/api/compiler/transformers/syntax-facts.js +258 -0
  328. package/dist/api/compiler/transformers/tagged-template.d.ts +17 -0
  329. package/dist/api/compiler/transformers/tagged-template.js +148 -0
  330. package/dist/api/compiler/transformers/transformer.d.ts +17 -0
  331. package/dist/api/compiler/transformers/transformer.js +54 -0
  332. package/dist/api/compiler/transformers/type-eraser.d.ts +21 -0
  333. package/dist/api/compiler/transformers/type-eraser.js +346 -0
  334. package/dist/api/compiler/transformers/type-serialization.d.ts +20 -0
  335. package/dist/api/compiler/transformers/type-serialization.js +347 -0
  336. package/dist/api/compiler/transformers/using.d.ts +56 -0
  337. package/dist/api/compiler/transformers/using.js +453 -0
  338. package/dist/api/compiler/transformers/utilities.d.ts +50 -0
  339. package/dist/api/compiler/transformers/utilities.js +347 -0
  340. package/dist/api/compiler/transformers/visitor-base.d.ts +6 -0
  341. package/dist/api/compiler/transformers/visitor-base.js +817 -0
  342. package/dist/api/compiler/transformers/visitor-hooks.d.ts +29 -0
  343. package/dist/api/compiler/transformers/visitor-hooks.js +189 -0
  344. package/dist/api/compiler/tsconfig.d.ts +177 -0
  345. package/dist/api/compiler/tsconfig.js +1311 -0
  346. package/dist/api/compiler/type-printer.d.ts +15 -0
  347. package/dist/api/compiler/type-printer.js +74 -0
  348. package/dist/api/compiler/types.d.ts +87 -0
  349. package/dist/api/compiler/types.js +23 -0
  350. package/dist/api/compiler/unicode-identifiers.d.ts +2 -0
  351. package/dist/api/compiler/unicode-identifiers.js +209 -0
  352. package/dist/api/compiler/unicode-properties.d.ts +8 -0
  353. package/dist/api/compiler/unicode-properties.js +531 -0
  354. package/dist/api/compiler/vfs-match.d.ts +24 -0
  355. package/dist/api/compiler/vfs-match.js +587 -0
  356. package/dist/api/library/ast.d.ts +3 -2
  357. package/dist/api/library/ast.generated.d.ts +127 -139
  358. package/dist/api/library/checker.d.ts +51 -0
  359. package/dist/api/library/checker.js +318 -0
  360. package/dist/api/library/diagnostics.d.ts +13 -0
  361. package/dist/api/library/diagnostics.js +50 -0
  362. package/dist/api/library/disk.d.ts +13 -0
  363. package/dist/api/library/disk.js +66 -0
  364. package/dist/api/library/errors.d.ts +13 -0
  365. package/dist/api/library/errors.js +24 -0
  366. package/dist/api/library/host.d.ts +24 -0
  367. package/dist/api/library/host.js +52 -0
  368. package/dist/api/library/index.d.ts +5 -1
  369. package/dist/api/library/index.js +4 -0
  370. package/dist/api/library/nodes.d.ts +51 -0
  371. package/dist/api/library/nodes.js +196 -0
  372. package/dist/api/library/options.d.ts +144 -0
  373. package/dist/api/library/options.js +308 -0
  374. package/dist/api/library/parse.d.ts +19 -0
  375. package/dist/api/library/parse.js +41 -0
  376. package/dist/api/library/program.d.ts +21 -0
  377. package/dist/api/library/program.js +234 -0
  378. package/dist/api/library/types.d.ts +14 -1
  379. package/package.json +12 -8
  380. package/src/compiler/ast-utilities.ts +548 -0
  381. package/src/compiler/ast.ts +12870 -0
  382. package/src/compiler/astnav.ts +799 -0
  383. package/src/compiler/binder-utilities.ts +1392 -0
  384. package/src/compiler/binder.ts +2707 -0
  385. package/src/compiler/build-info.ts +1197 -0
  386. package/src/compiler/character-codes.ts +323 -0
  387. package/src/compiler/checker-calls.ts +2155 -0
  388. package/src/compiler/checker-classes.ts +706 -0
  389. package/src/compiler/checker-contextual.ts +1457 -0
  390. package/src/compiler/checker-declaration-order.ts +438 -0
  391. package/src/compiler/checker-declarations.ts +1201 -0
  392. package/src/compiler/checker-declared-types.ts +919 -0
  393. package/src/compiler/checker-decorators.ts +694 -0
  394. package/src/compiler/checker-deprecation.ts +355 -0
  395. package/src/compiler/checker-destructuring.ts +805 -0
  396. package/src/compiler/checker-elaboration.ts +477 -0
  397. package/src/compiler/checker-emit-helpers.ts +224 -0
  398. package/src/compiler/checker-emit-resolver.ts +769 -0
  399. package/src/compiler/checker-evaluator.ts +243 -0
  400. package/src/compiler/checker-expressions.ts +1831 -0
  401. package/src/compiler/checker-features.ts +361 -0
  402. package/src/compiler/checker-flow.ts +394 -0
  403. package/src/compiler/checker-functions.ts +1296 -0
  404. package/src/compiler/checker-generated-code.ts +227 -0
  405. package/src/compiler/checker-globals.ts +52 -0
  406. package/src/compiler/checker-grammar.ts +3596 -0
  407. package/src/compiler/checker-heritage.ts +1240 -0
  408. package/src/compiler/checker-inference.ts +2584 -0
  409. package/src/compiler/checker-iteration.ts +1206 -0
  410. package/src/compiler/checker-javascript.ts +502 -0
  411. package/src/compiler/checker-jsdoc.ts +360 -0
  412. package/src/compiler/checker-jsx.ts +1928 -0
  413. package/src/compiler/checker-literals.ts +61 -0
  414. package/src/compiler/checker-members.ts +2480 -0
  415. package/src/compiler/checker-modules.ts +2896 -0
  416. package/src/compiler/checker-narrowing.ts +3230 -0
  417. package/src/compiler/checker-object-literals.ts +591 -0
  418. package/src/compiler/checker-operators.ts +1422 -0
  419. package/src/compiler/checker-overloads.ts +328 -0
  420. package/src/compiler/checker-property-access.ts +906 -0
  421. package/src/compiler/checker-services.ts +1149 -0
  422. package/src/compiler/checker-signatures.ts +1032 -0
  423. package/src/compiler/checker-source-file.ts +732 -0
  424. package/src/compiler/checker-statements.ts +292 -0
  425. package/src/compiler/checker-super.ts +261 -0
  426. package/src/compiler/checker-symbol-types.ts +1187 -0
  427. package/src/compiler/checker-symbols.ts +2157 -0
  428. package/src/compiler/checker-type-factory.ts +2616 -0
  429. package/src/compiler/checker-type-nodes.ts +1033 -0
  430. package/src/compiler/checker-type-operators.ts +2510 -0
  431. package/src/compiler/checker-types.ts +2520 -0
  432. package/src/compiler/checker-unused.ts +642 -0
  433. package/src/compiler/checker-utilities.ts +161 -0
  434. package/src/compiler/checker.ts +1138 -0
  435. package/src/compiler/command-line.ts +436 -0
  436. package/src/compiler/compile-program.ts +439 -0
  437. package/src/compiler/decoder.ts +1209 -0
  438. package/src/compiler/diagnostic-locales.ts +86 -0
  439. package/src/compiler/diagnostic-messages.ts +2349 -0
  440. package/src/compiler/diagnostics.ts +858 -0
  441. package/src/compiler/emitter.ts +434 -0
  442. package/src/compiler/encoder.ts +1945 -0
  443. package/src/compiler/file-include.ts +741 -0
  444. package/src/compiler/file-loader.ts +1597 -0
  445. package/src/compiler/file-system.ts +143 -0
  446. package/src/compiler/flow.ts +89 -0
  447. package/src/compiler/help.ts +473 -0
  448. package/src/compiler/incremental.ts +2818 -0
  449. package/src/compiler/init.ts +141 -0
  450. package/src/compiler/instantiation.ts +938 -0
  451. package/src/compiler/jsdoc.ts +1386 -0
  452. package/src/compiler/link-tables.ts +343 -0
  453. package/src/compiler/locale-data.ts +203 -0
  454. package/src/compiler/locale.ts +307 -0
  455. package/src/compiler/locales/cs-CZ.ts +5 -0
  456. package/src/compiler/locales/de-DE.ts +5 -0
  457. package/src/compiler/locales/es-ES.ts +5 -0
  458. package/src/compiler/locales/fr-FR.ts +5 -0
  459. package/src/compiler/locales/it-IT.ts +5 -0
  460. package/src/compiler/locales/ja-JP.ts +5 -0
  461. package/src/compiler/locales/ko-KR.ts +5 -0
  462. package/src/compiler/locales/pl-PL.ts +5 -0
  463. package/src/compiler/locales/pt-BR.ts +5 -0
  464. package/src/compiler/locales/ru-RU.ts +5 -0
  465. package/src/compiler/locales/tr-TR.ts +5 -0
  466. package/src/compiler/locales/zh-CN.ts +5 -0
  467. package/src/compiler/locales/zh-TW.ts +5 -0
  468. package/src/compiler/module-resolution-types.ts +243 -0
  469. package/src/compiler/module-resolution.ts +2072 -0
  470. package/src/compiler/module-specifiers.ts +1491 -0
  471. package/src/compiler/name-resolver.ts +646 -0
  472. package/src/compiler/node-builder-names.ts +1071 -0
  473. package/src/compiler/node-builder-pseudo.ts +892 -0
  474. package/src/compiler/node-builder-reuse.ts +764 -0
  475. package/src/compiler/node-builder.ts +3433 -0
  476. package/src/compiler/option-declarations.ts +1560 -0
  477. package/src/compiler/options.ts +1576 -0
  478. package/src/compiler/output-paths.ts +334 -0
  479. package/src/compiler/package-json.ts +1083 -0
  480. package/src/compiler/parallel-check.ts +1954 -0
  481. package/src/compiler/parallel-parse.ts +595 -0
  482. package/src/compiler/parse-thread.ts +136 -0
  483. package/src/compiler/parser.ts +7766 -0
  484. package/src/compiler/path.ts +717 -0
  485. package/src/compiler/printer/async-helpers.ts +183 -0
  486. package/src/compiler/printer/auto-generate.ts +27 -0
  487. package/src/compiler/printer/decorator-helpers.ts +218 -0
  488. package/src/compiler/printer/emit-context.ts +684 -0
  489. package/src/compiler/printer/emit-flags.ts +64 -0
  490. package/src/compiler/printer/factory-base.ts +2577 -0
  491. package/src/compiler/printer/factory.ts +764 -0
  492. package/src/compiler/printer/helpers.ts +291 -0
  493. package/src/compiler/printer/name-generator.ts +372 -0
  494. package/src/compiler/printer/printer.ts +5072 -0
  495. package/src/compiler/printer/text-writer.ts +183 -0
  496. package/src/compiler/printer/utilities.ts +884 -0
  497. package/src/compiler/program-checker.ts +594 -0
  498. package/src/compiler/program-utilities.ts +435 -0
  499. package/src/compiler/program.ts +1426 -0
  500. package/src/compiler/pseudo-bigint.ts +62 -0
  501. package/src/compiler/regexp-checker.ts +1142 -0
  502. package/src/compiler/relations.ts +5149 -0
  503. package/src/compiler/reparser.ts +1566 -0
  504. package/src/compiler/scanner.ts +2951 -0
  505. package/src/compiler/show-config.ts +239 -0
  506. package/src/compiler/side-state.ts +125 -0
  507. package/src/compiler/sourcemap.ts +366 -0
  508. package/src/compiler/spelling.ts +122 -0
  509. package/src/compiler/symbol-accessibility.ts +1166 -0
  510. package/src/compiler/symbol.ts +557 -0
  511. package/src/compiler/symlinks.ts +137 -0
  512. package/src/compiler/syntax-kind.ts +391 -0
  513. package/src/compiler/thread-entry.ts +191 -0
  514. package/src/compiler/timeline.ts +53 -0
  515. package/src/compiler/transformers/alias-references.ts +757 -0
  516. package/src/compiler/transformers/async-utilities.ts +335 -0
  517. package/src/compiler/transformers/async.ts +838 -0
  518. package/src/compiler/transformers/class-fields.ts +2967 -0
  519. package/src/compiler/transformers/class-utilities.ts +324 -0
  520. package/src/compiler/transformers/commonjs-module.ts +1621 -0
  521. package/src/compiler/transformers/const-enum-inliner.ts +50 -0
  522. package/src/compiler/transformers/declarations-diagnostics.ts +833 -0
  523. package/src/compiler/transformers/declarations-pseudo.ts +969 -0
  524. package/src/compiler/transformers/declarations-resolver.ts +249 -0
  525. package/src/compiler/transformers/declarations-syntactic.ts +1867 -0
  526. package/src/compiler/transformers/declarations-tracker.ts +269 -0
  527. package/src/compiler/transformers/declarations.ts +3120 -0
  528. package/src/compiler/transformers/decorator-metadata.ts +697 -0
  529. package/src/compiler/transformers/decorator-utilities.ts +283 -0
  530. package/src/compiler/transformers/destructuring.ts +708 -0
  531. package/src/compiler/transformers/downlevel.ts +50 -0
  532. package/src/compiler/transformers/emit-resolver.ts +258 -0
  533. package/src/compiler/transformers/es-decorators.ts +2682 -0
  534. package/src/compiler/transformers/exponentiation.ts +80 -0
  535. package/src/compiler/transformers/external-module-info.ts +412 -0
  536. package/src/compiler/transformers/for-await.ts +687 -0
  537. package/src/compiler/transformers/import-elision.ts +152 -0
  538. package/src/compiler/transformers/jsx-entities.ts +256 -0
  539. package/src/compiler/transformers/jsx.ts +824 -0
  540. package/src/compiler/transformers/legacy-decorators.ts +726 -0
  541. package/src/compiler/transformers/logical-assignment.ts +75 -0
  542. package/src/compiler/transformers/module-utilities.ts +42 -0
  543. package/src/compiler/transformers/module.ts +474 -0
  544. package/src/compiler/transformers/named-evaluation.ts +389 -0
  545. package/src/compiler/transformers/nullish-coalescing.ts +35 -0
  546. package/src/compiler/transformers/object-rest-spread.ts +577 -0
  547. package/src/compiler/transformers/optional-catch.ts +29 -0
  548. package/src/compiler/transformers/optional-chain.ts +246 -0
  549. package/src/compiler/transformers/reference-resolver.ts +1213 -0
  550. package/src/compiler/transformers/runtime-syntax.ts +942 -0
  551. package/src/compiler/transformers/subtree-facts.ts +253 -0
  552. package/src/compiler/transformers/syntax-facts.ts +358 -0
  553. package/src/compiler/transformers/tagged-template.ts +167 -0
  554. package/src/compiler/transformers/transformer.ts +56 -0
  555. package/src/compiler/transformers/type-eraser.ts +520 -0
  556. package/src/compiler/transformers/type-serialization.ts +374 -0
  557. package/src/compiler/transformers/using.ts +613 -0
  558. package/src/compiler/transformers/utilities.ts +419 -0
  559. package/src/compiler/transformers/visitor-base.ts +1601 -0
  560. package/src/compiler/transformers/visitor-hooks.ts +252 -0
  561. package/src/compiler/tsc-build.ts +1422 -0
  562. package/src/compiler/tsc-cli.ts +669 -0
  563. package/src/compiler/tsc-compile.ts +446 -0
  564. package/src/compiler/tsc-watch.ts +922 -0
  565. package/src/compiler/tsconfig.ts +1574 -0
  566. package/src/compiler/type-printer.ts +110 -0
  567. package/src/compiler/types.ts +115 -0
  568. package/src/compiler/unicode-identifiers.ts +212 -0
  569. package/src/compiler/unicode-properties.ts +537 -0
  570. package/src/compiler/vfs-match.ts +597 -0
  571. package/src/compiler/xxh3.ts +650 -0
  572. package/src/library/ast.generated.ts +141 -167
  573. package/src/library/ast.ts +4 -1
  574. package/src/library/checker.ts +384 -0
  575. package/src/library/diagnostics.ts +72 -0
  576. package/src/library/disk.ts +73 -0
  577. package/src/library/errors.ts +26 -0
  578. package/src/library/host.ts +63 -0
  579. package/src/library/index.ts +21 -0
  580. package/src/library/nodes.ts +232 -0
  581. package/src/library/options.ts +449 -0
  582. package/src/library/parse.ts +63 -0
  583. package/src/library/program.ts +293 -0
  584. package/src/library/types.ts +14 -1
@@ -0,0 +1,3230 @@
1
+ // Control flow analysis: the type of a reference at a position, walking the binder's flow graph
2
+ // backwards from the reference through assignments, conditions, calls and labels.
3
+ import { sideOf } from './side-state.js';
4
+ import {
5
+ type ForInOrOfStatement,
6
+ type MetaProperty,
7
+ type BindingElement,
8
+ type VariableDeclaration,
9
+ type Identifier,
10
+ getName,
11
+ type BinaryExpression,
12
+ type ElementAccessExpression,
13
+ type Node,
14
+ type PrefixUnaryExpression,
15
+ type PropertyAccessExpression,
16
+ type QualifiedName,
17
+ type SwitchStatement,
18
+ type ShorthandPropertyAssignment,
19
+ type CaseOrDefaultClause,
20
+ getExpression,
21
+ getFlowNode,
22
+ getInitializer,
23
+ getText,
24
+ ExportDeclaration,
25
+ ExportSpecifier,
26
+ ModifierFlags,
27
+ NodeFlags,
28
+ NodeVisitor,
29
+ getArguments,
30
+ getDotDotDotToken,
31
+ getParameters,
32
+ getElements,
33
+ getType,
34
+ getStatements,
35
+ } from './ast.js';
36
+ import { FlowFlags, type FlowNode, FlowReduceLabel, FlowSwitchClause } from './flow.js';
37
+ import { SyntaxKind } from './syntax-kind.js';
38
+ import type { Checker } from './checker.js';
39
+ import {
40
+ CachedTypeKind,
41
+ cachedTypeKey,
42
+ cachedTypePairKey,
43
+ type LiteralType,
44
+ type Type,
45
+ TypeFlags,
46
+ type UnionType,
47
+ CheckMode,
48
+ type EvolvingArrayType,
49
+ InterfaceType,
50
+ NodeCheckFlags,
51
+ ObjectFlags,
52
+ Signature,
53
+ SignatureKind,
54
+ TypePredicate,
55
+ TypePredicateKind,
56
+ } from './checker-types.js';
57
+ import { getSymbolId, CheckFlags, InternalSymbolName, SymbolFlags, type Symbol } from './symbol.js';
58
+ import { getNodeId } from './ast.js';
59
+ import {
60
+ TypeFacts,
61
+ getAdjustedTypeWithFacts,
62
+ getNonNullableType,
63
+ getTypeFacts,
64
+ getTypeWithFacts,
65
+ hasTypeFacts,
66
+ } from './checker-flow.js';
67
+ import {
68
+ UnionReduction,
69
+ everyType,
70
+ filterType,
71
+ getBaseTypeOfLiteralType,
72
+ getFreshTypeOfLiteralType,
73
+ getIntersectionType,
74
+ getRegularTypeOfLiteralType,
75
+ getUnionType,
76
+ getUnionTypeEx,
77
+ getWidenedLiteralType,
78
+ isEmptyAnonymousObjectType,
79
+ isFreshLiteralType,
80
+ isLiteralType,
81
+ isPatternLiteralType,
82
+ isUnitType,
83
+ mapType,
84
+ removeType,
85
+ someType,
86
+ typesOf,
87
+ containsMissingType,
88
+ getNumberLiteralType,
89
+ createArrayType,
90
+ isTupleType,
91
+ newObjectType,
92
+ } from './checker-type-factory.js';
93
+ import {
94
+ areTypesComparable,
95
+ isDiscriminantProperty,
96
+ isTypeAssignableTo,
97
+ isTypeDerivedFrom,
98
+ isTypeRelatedTo,
99
+ isTypeStrictSubtypeOf,
100
+ isTypeSubsetOf,
101
+ isTypeSubtypeOf,
102
+ } from './relations.js';
103
+ import {
104
+ checkExpression,
105
+ checkExpressionCached,
106
+ checkExpressionEx,
107
+ checkNonNullExpression,
108
+ checkNonNullType,
109
+ getNarrowableTypeForReference,
110
+ someTypeIsGenericWithUnionConstraint,
111
+ getResolvedSymbol,
112
+ getTypeOfExpression,
113
+ isThisInTypeQuery,
114
+ isTupleLikeType,
115
+ } from './checker-expressions.js';
116
+ import { isBlockScopedNameDeclaredBeforeUse } from './checker-declaration-order.js';
117
+ import {
118
+ getContextualSignature,
119
+ getInferenceContext,
120
+ isContextSensitiveFunctionOrObjectLiteralMethod,
121
+ } from './checker-contextual.js';
122
+ import { instantiateType } from './instantiation.js';
123
+ import { IterationUse, checkIteratedTypeOrElementType } from './checker-iteration.js';
124
+ import { checkSuperExpression } from './checker-super.js';
125
+ import { getSymbolNameForPrivateIdentifier } from './binder.js';
126
+ import { isTypeAssignableToKindEx } from './checker-type-operators.js';
127
+ import { getRegularTypeOfObjectLiteral } from './checker-literals.js';
128
+ import { checkRightHandSideOfForOf } from './checker-statements.js';
129
+ import {
130
+ getApparentType,
131
+ getApplicableIndexInfoForName,
132
+ getBaseConstraintOfType,
133
+ getPropertiesOfType,
134
+ getPropertyOfType,
135
+ getReducedApparentType,
136
+ getSignaturesOfType,
137
+ getTypeOfPropertyOfType,
138
+ mapToBaseConstraintOrType,
139
+ } from './checker-members.js';
140
+ import {
141
+ getAssignmentTarget,
142
+ isAssignmentTarget,
143
+ isPushOrUnshiftIdentifier,
144
+ getCombinedModifierFlags,
145
+ hasStaticModifier,
146
+ getCombinedNodeFlags,
147
+ getImmediatelyInvokedFunctionExpression,
148
+ getRootDeclaration,
149
+ getThisContainer,
150
+ isAssignmentExpression,
151
+ isClassLike,
152
+ isEntityNameExpression,
153
+ isObjectLiteralMethod,
154
+ isExpressionOfOptionalChainRoot,
155
+ isGlobalSourceFile,
156
+ isLogicalOrCoalescingAssignmentOperator,
157
+ isOptionalChain,
158
+ isStatic,
159
+ skipParentheses,
160
+ getRangeOfTokenAtPosition,
161
+ getSourceFileOfNode,
162
+ } from './binder-utilities.js';
163
+ import { getDeclaredTypeOfSymbol, isConstructorType } from './checker-declared-types.js';
164
+ import {
165
+ getErasedSignature,
166
+ getReturnTypeFromAnnotation,
167
+ getReturnTypeOfSignature,
168
+ getSignatureFromDeclaration,
169
+ getTypePredicateOfSignature,
170
+ } from './checker-signatures.js';
171
+ import {
172
+ getExportSymbolOfValueSymbolIfExported,
173
+ getSymbolOfDeclaration,
174
+ resolveEntityName,
175
+ resolveSymbol,
176
+ getGlobalTypeAliasSymbol,
177
+ } from './checker-symbols.js';
178
+ import { getOptionalType, getTypeOfSymbol, isReadonlySymbol } from './checker-symbol-types.js';
179
+ import { getPropertyNameFromType, isTypeUsableAsPropertyName, maybeTypeOfKind } from './checker-utilities.js';
180
+ import { getTypeFromTypeNode, getTypeAliasInstantiation } from './checker-type-nodes.js';
181
+ import { isFunctionLike, isInJSFile } from './ast-utilities.js';
182
+ import { Diagnostic } from './diagnostics.js';
183
+ import { Diagnostics } from './diagnostic-messages.js';
184
+ import { getOptionalExpressionType, getResolvedSignature } from './checker-calls.js';
185
+ import { getSymbolHasInstanceMethodOfObjectType } from './checker-operators.js';
186
+ import { getSymbolForPrivateIdentifierExpression } from './checker-property-access.js';
187
+ import {
188
+ getIndexedAccessType,
189
+ getLiteralTypeFromPropertyName,
190
+ getTupleElementTypeOutOfStartCount,
191
+ } from './checker-type-operators.js';
192
+ import {
193
+ getBindingElementTypeFromParentType,
194
+ getNonUndefinedType,
195
+ getTypeForBindingElementParent,
196
+ } from './checker-destructuring.js';
197
+
198
+ /**
199
+ * The number of shared nodes a walk caches before it indexes them. A walk through many consecutive
200
+ * conditions on one reference caches a node for each, and searching them all for each node made
201
+ * such walks cubic in the number of conditions. A walk's own entries stay in the cache until it
202
+ * ends, so a walk with at least this many is indexed.
203
+ */
204
+ const sharedFlowIndexThreshold = 128;
205
+
206
+ /** Indexes the entries of walk `f` in the shared flow cache by their first occurrence. */
207
+ function indexSharedFlows(c: Checker, f: FlowState, walkDepth: number): void {
208
+ while (c.sharedFlowIndexes.length <= walkDepth) c.sharedFlowIndexes.push(new Map<FlowNode, number>());
209
+ const index = c.sharedFlowIndexes[walkDepth]!;
210
+ index.clear();
211
+ for (let i = f.sharedFlowStart; i < c.sharedFlowCount; i++) {
212
+ const node = c.sharedFlowNodes[i]!;
213
+ if (!index.has(node)) index.set(node, i);
214
+ }
215
+ }
216
+
217
+ /** The state of one `getFlowTypeOfReference` walk. `incomplete` describes the last returned type. */
218
+ export class FlowState {
219
+ reference: Node;
220
+ declaredType: Type;
221
+ initialType: Type;
222
+ flowContainer: Node | undefined;
223
+ refKey: string | undefined = undefined;
224
+ depth = 0;
225
+ sharedFlowStart = 0;
226
+ incomplete = false;
227
+ /** The flow nodes visited, and the deepest nesting of the walk. */
228
+ steps = 0;
229
+ maxDepth = 0;
230
+ /** Whether this walk may be kept and end on a kept one (`FlowWalk`), and whether it looked one up. */
231
+ keepsWalk = false;
232
+ lookedUp = false;
233
+ /** The reference's last long walk, which this walk may end on. */
234
+ walk: FlowWalk | undefined = undefined;
235
+ /** The node where this walk would be kept from: see `flowWalkAnchorSteps`. */
236
+ anchor: FlowNode | undefined = undefined;
237
+ /** Whether the result depends on where the reference is, not only on its key. */
238
+ positional = false;
239
+
240
+ constructor(reference: Node, declaredType: Type, initialType: Type, flowContainer: Node | undefined) {
241
+ this.reference = reference;
242
+ this.declaredType = declaredType;
243
+ this.initialType = initialType;
244
+ this.flowContainer = flowContainer;
245
+ }
246
+
247
+ /** Prepares a free flow state for another walk. */
248
+ reset(reference: Node, declaredType: Type, initialType: Type, flowContainer: Node | undefined): void {
249
+ this.reference = reference;
250
+ this.declaredType = declaredType;
251
+ this.initialType = initialType;
252
+ this.flowContainer = flowContainer;
253
+ this.refKey = undefined;
254
+ this.depth = 0;
255
+ this.sharedFlowStart = 0;
256
+ this.incomplete = false;
257
+ this.steps = 0;
258
+ this.maxDepth = 0;
259
+ this.keepsWalk = false;
260
+ this.lookedUp = false;
261
+ this.walk = undefined;
262
+ this.anchor = undefined;
263
+ this.positional = false;
264
+ }
265
+ }
266
+
267
+ /**
268
+ * A node of a reference's last long walk, and the walk's result. Without loops or reduce labels in
269
+ * effect, the type of a reference at a flow node doesn't change, so a later walk that reaches `start`
270
+ * ends there. In a long list of top-level declarations, each reference otherwise walks back over
271
+ * every one before it.
272
+ */
273
+ export class FlowWalk {
274
+ start: FlowNode;
275
+ type: Type;
276
+ /** The deepest nesting of a walk from `start`, which reaches the depth limit the same way. */
277
+ depth: number;
278
+
279
+ constructor(start: FlowNode, type: Type, depth: number) {
280
+ this.start = start;
281
+ this.type = type;
282
+ this.depth = depth;
283
+ }
284
+ }
285
+
286
+ /** Walks shorter than this aren't kept. */
287
+ const minFlowWalkSteps = 32;
288
+
289
+ /**
290
+ * The step of a frame of a walk at which the walk looks up the reference's kept walk; in the first
291
+ * frame, also the node it would be kept from. Every node a frame passes before the last one leaves
292
+ * the type unchanged, so the type there is the walk's result. Shorter walks don't compute the
293
+ * reference's key. A later walk that passes this walk's start reaches the node after this many steps
294
+ * or more, once it has looked.
295
+ */
296
+ const flowWalkAnchorSteps = 16;
297
+
298
+ /**
299
+ * Whether `node` is an identifier, `this`, or property and element accesses on one. Walks of such
300
+ * references with the same key (`getFlowReferenceKey`) go the same way; with parentheses or a
301
+ * non-null assertion in between, a reference has the key of the one without, but not its walk.
302
+ */
303
+ function isDottedReference(node: Node): boolean {
304
+ let n = node;
305
+ for (;;) {
306
+ switch (n.kind) {
307
+ case SyntaxKind.Identifier:
308
+ return !isThisInTypeQuery(n);
309
+ case SyntaxKind.ThisKeyword:
310
+ return true;
311
+ case SyntaxKind.PropertyAccessExpression:
312
+ case SyntaxKind.ElementAccessExpression:
313
+ n = getExpression(n)!;
314
+ break;
315
+ default:
316
+ return false;
317
+ }
318
+ }
319
+ }
320
+
321
+ /**
322
+ * Whether an element access in `node` names a property with a character that keys use as a
323
+ * separator (`.`, `@`, `#`). Its key can then be another reference's, as `o["a.b"]` has the key of
324
+ * `o.a.b`, so its walks aren't kept.
325
+ */
326
+ function hasKeyCharacterInName(c: Checker, node: Node): boolean {
327
+ let n = node;
328
+ while (n.kind === SyntaxKind.PropertyAccessExpression || n.kind === SyntaxKind.ElementAccessExpression) {
329
+ if (n.kind === SyntaxKind.ElementAccessExpression) {
330
+ const name = getAccessedPropertyName(c, n);
331
+ if (name !== undefined && /[.@#]/.test(name)) return true;
332
+ }
333
+ n = getExpression(n)!;
334
+ }
335
+ return false;
336
+ }
337
+
338
+ /** A loop junction being analyzed for a reference, with the types seen on its paths so far. */
339
+ export class FlowLoopInfo {
340
+ readonly flow: FlowNode;
341
+ readonly refKey: string;
342
+ readonly types: Type[];
343
+
344
+ constructor(flow: FlowNode, refKey: string, types: Type[]) {
345
+ this.flow = flow;
346
+ this.refKey = refKey;
347
+ this.types = types;
348
+ }
349
+ }
350
+
351
+ /** The type of `reference` at its flow position, narrowed from `declaredType` starting at `initialType`. */
352
+ export function getFlowTypeOfReference(
353
+ c: Checker,
354
+ reference: Node,
355
+ declaredType: Type,
356
+ initialType: Type,
357
+ flowContainer: Node | undefined,
358
+ ): Type {
359
+ return getFlowTypeOfReferenceAt(c, reference, declaredType, initialType, flowContainer, getFlowNode(reference));
360
+ }
361
+
362
+ /** `getFlowTypeOfReference` at `flowNode`, for pseudo-references such as binding patterns. */
363
+ export function getFlowTypeOfReferenceAt(
364
+ c: Checker,
365
+ reference: Node,
366
+ declaredType: Type,
367
+ initialType: Type,
368
+ flowContainer: Node | undefined,
369
+ flowNode: FlowNode | undefined,
370
+ ): Type {
371
+ if (c.flowAnalysisDisabled) return c.errorType;
372
+ if (flowNode === undefined) return declaredType;
373
+ let f: FlowState;
374
+ const stateDepth = c.flowStateDepth;
375
+ if (stateDepth < c.flowStates.length) {
376
+ f = c.flowStates[stateDepth]!;
377
+ f.reset(reference, declaredType, initialType, flowContainer);
378
+ } else {
379
+ f = new FlowState(reference, declaredType, initialType, flowContainer);
380
+ c.flowStates.push(f);
381
+ }
382
+ c.flowStateDepth = stateDepth + 1;
383
+ f.sharedFlowStart = c.sharedFlowCount;
384
+ c.flowInvocationCount++;
385
+ f.keepsWalk =
386
+ c.flowLoopStack.length === 0 &&
387
+ c.flowReduceLabels.length === 0 &&
388
+ c.inlineLevel === 0 &&
389
+ isDottedReference(reference);
390
+ const cycles = c.resolutionCycleCount;
391
+ const evolvedType = getTypeAtFlowNode(c, f, flowNode);
392
+ const anchor = f.anchor;
393
+ if (
394
+ anchor !== undefined &&
395
+ f.steps >= minFlowWalkSteps &&
396
+ !f.incomplete &&
397
+ !f.positional &&
398
+ !c.flowAnalysisDisabled &&
399
+ c.resolutionCycleCount === cycles
400
+ ) {
401
+ const walk = f.walk;
402
+ if (walk !== undefined) {
403
+ walk.start = anchor;
404
+ walk.type = evolvedType;
405
+ walk.depth = f.maxDepth;
406
+ } else c.flowWalks.set(f.refKey!, new FlowWalk(anchor, evolvedType, f.maxDepth));
407
+ }
408
+ c.sharedFlowCount = f.sharedFlowStart;
409
+ c.flowStateDepth = stateDepth;
410
+ // `x` in `x.length`, `x.push(v)`, `x.unshift(v)` or `x[n] = v` stays `any[]` so empty arrays may be
411
+ // operated on and new element types inferred without implicit any or mismatch errors.
412
+ const resultType =
413
+ (evolvedType.objectFlags & ObjectFlags.EvolvingArray) !== 0 && isEvolvingArrayOperationTarget(c, reference)
414
+ ? c.autoArrayType
415
+ : finalizeEvolvingArrayType(c, evolvedType);
416
+ if (
417
+ resultType === c.unreachableNeverType ||
418
+ (reference.parent !== undefined &&
419
+ reference.parent.kind === SyntaxKind.NonNullExpression &&
420
+ (resultType.flags & TypeFlags.Never) === 0 &&
421
+ (getTypeWithFacts(c, resultType, TypeFacts.NEUndefinedOrNull).flags & TypeFlags.Never) !== 0)
422
+ )
423
+ return declaredType;
424
+ return resultType;
425
+ }
426
+
427
+ function newFlowType(c: Checker, f: FlowState, t: Type, incomplete: boolean): Type {
428
+ f.incomplete = incomplete;
429
+ return incomplete && (t.flags & TypeFlags.Never) !== 0 ? c.silentNeverType : t;
430
+ }
431
+
432
+ function complete(f: FlowState, t: Type): Type {
433
+ f.incomplete = false;
434
+ return t;
435
+ }
436
+
437
+ export function getTypeAtFlowNode(c: Checker, f: FlowState, start: FlowNode): Type {
438
+ if (f.depth === 2000) {
439
+ c.flowAnalysisDisabled = true;
440
+ reportFlowControlError(c, f.reference);
441
+ return complete(f, c.errorType);
442
+ }
443
+ f.depth++;
444
+ if (f.depth > f.maxDepth) f.maxDepth = f.depth;
445
+ let flow = start;
446
+ let sharedFlow: FlowNode | undefined = undefined;
447
+ let frameSteps = 0;
448
+ for (;;) {
449
+ f.steps++;
450
+ if (++frameSteps === flowWalkAnchorSteps && f.keepsWalk && !f.lookedUp) {
451
+ f.lookedUp = true;
452
+ if (f.refKey === undefined) f.refKey = getFlowReferenceKey(c, f);
453
+ if (f.refKey !== '' && !hasKeyCharacterInName(c, f.reference)) {
454
+ f.walk = c.flowWalks.get(f.refKey);
455
+ // Only the first frame's nodes have the walk's result as their type.
456
+ if (f.depth === 1) f.anchor = flow;
457
+ }
458
+ }
459
+ const walk = f.walk;
460
+ const flags = flow.flags;
461
+ if ((flags & FlowFlags.Shared) !== 0) {
462
+ // Shared nodes are cached for the duration of one walk.
463
+ if (c.sharedFlowCount - f.sharedFlowStart >= sharedFlowIndexThreshold) {
464
+ const i = c.sharedFlowIndexes[c.flowStateDepth - 1]!.get(flow);
465
+ if (i !== undefined) {
466
+ f.depth--;
467
+ f.incomplete = c.sharedFlowIncomplete[i]!;
468
+ return c.sharedFlowTypes[i]!;
469
+ }
470
+ } else
471
+ for (let i = f.sharedFlowStart; i < c.sharedFlowCount; i++) {
472
+ if (c.sharedFlowNodes[i]! === flow) {
473
+ f.depth--;
474
+ f.incomplete = c.sharedFlowIncomplete[i]!;
475
+ return c.sharedFlowTypes[i]!;
476
+ }
477
+ }
478
+ sharedFlow = flow;
479
+ }
480
+ let t: Type;
481
+ if (
482
+ walk !== undefined &&
483
+ flow === walk.start &&
484
+ c.flowLoopStack.length === 0 &&
485
+ c.flowReduceLabels.length === 0 &&
486
+ c.inlineLevel === 0 &&
487
+ f.depth + walk.depth - 1 <= 2000
488
+ ) {
489
+ if (f.depth + walk.depth - 1 > f.maxDepth) f.maxDepth = f.depth + walk.depth - 1;
490
+ t = complete(f, walk.type);
491
+ } else if ((flags & FlowFlags.Assignment) !== 0) {
492
+ const assigned = getTypeAtFlowAssignment(c, f, flow);
493
+ if (assigned === undefined) {
494
+ flow = flow.antecedent!;
495
+ continue;
496
+ }
497
+ t = assigned;
498
+ } else if ((flags & FlowFlags.Call) !== 0) {
499
+ const narrowed = getTypeAtFlowCall(c, f, flow);
500
+ if (narrowed === undefined) {
501
+ flow = flow.antecedent!;
502
+ continue;
503
+ }
504
+ t = narrowed;
505
+ } else if ((flags & FlowFlags.Condition) !== 0) t = getTypeAtFlowCondition(c, f, flow);
506
+ else if ((flags & FlowFlags.SwitchClause) !== 0) t = getTypeAtSwitchClause(c, f, flow as FlowSwitchClause);
507
+ else if ((flags & FlowFlags.BranchLabel) !== 0) {
508
+ const antecedents = getBranchLabelAntecedents(c, flow);
509
+ if (antecedents.length === 1) {
510
+ flow = antecedents[0]!;
511
+ continue;
512
+ }
513
+ t = getTypeAtFlowBranchLabel(c, f, antecedents);
514
+ } else if ((flags & FlowFlags.LoopLabel) !== 0) {
515
+ const antecedents = flow.antecedents!;
516
+ if (antecedents.length === 1) {
517
+ flow = antecedents[0]!;
518
+ continue;
519
+ }
520
+ t = getTypeAtFlowLoopLabel(c, f, flow);
521
+ } else if ((flags & FlowFlags.ArrayMutation) !== 0) {
522
+ const mutated = getTypeAtFlowArrayMutation(c, f, flow);
523
+ if (mutated === undefined) {
524
+ flow = flow.antecedent!;
525
+ continue;
526
+ }
527
+ t = mutated;
528
+ } else if ((flags & FlowFlags.ReduceLabel) !== 0) {
529
+ c.flowReduceLabels.push(flow as FlowReduceLabel);
530
+ t = getTypeAtFlowNode(c, f, flow.antecedent!);
531
+ c.flowReduceLabels.pop();
532
+ } else if ((flags & FlowFlags.Start) !== 0) {
533
+ // Continue with the containing function's flow when the reference is captured.
534
+ const container = flow.node;
535
+ if (
536
+ container !== undefined &&
537
+ container !== f.flowContainer &&
538
+ f.reference.kind !== SyntaxKind.PropertyAccessExpression &&
539
+ f.reference.kind !== SyntaxKind.ElementAccessExpression &&
540
+ !(f.reference.kind === SyntaxKind.ThisKeyword && container.kind !== SyntaxKind.ArrowFunction)
541
+ ) {
542
+ const outer = getFlowNode(container);
543
+ if (outer !== undefined) {
544
+ flow = outer;
545
+ continue;
546
+ }
547
+ }
548
+ t = complete(f, f.initialType);
549
+ } else {
550
+ // Unreachable code; errors are reported by the binder.
551
+ t = complete(f, convertAutoToAny(c, f.declaredType));
552
+ }
553
+ if (sharedFlow !== undefined) {
554
+ const count = c.sharedFlowCount;
555
+ if (count < c.sharedFlowNodes.length) {
556
+ c.sharedFlowNodes[count] = sharedFlow;
557
+ c.sharedFlowTypes[count] = t;
558
+ c.sharedFlowIncomplete[count] = f.incomplete;
559
+ } else {
560
+ c.sharedFlowNodes.push(sharedFlow);
561
+ c.sharedFlowTypes.push(t);
562
+ c.sharedFlowIncomplete.push(f.incomplete);
563
+ }
564
+ c.sharedFlowCount = count + 1;
565
+ const own = count + 1 - f.sharedFlowStart;
566
+ if (own > sharedFlowIndexThreshold) {
567
+ const index = c.sharedFlowIndexes[c.flowStateDepth - 1]!;
568
+ if (!index.has(sharedFlow)) index.set(sharedFlow, count);
569
+ } else if (own === sharedFlowIndexThreshold) indexSharedFlows(c, f, c.flowStateDepth - 1);
570
+ }
571
+ f.depth--;
572
+ return t;
573
+ }
574
+ }
575
+
576
+ export function convertAutoToAny(c: Checker, t: Type): Type {
577
+ if (t === c.autoType) return c.anyType;
578
+ if (t === c.autoArrayType) return c.anyArrayType;
579
+ return t;
580
+ }
581
+
582
+ /** A branch label's antecedents, as limited by the innermost reduce label being passed that targets it. */
583
+ export function getBranchLabelAntecedents(c: Checker, flow: FlowNode): FlowNode[] {
584
+ const reduceLabels = c.flowReduceLabels;
585
+ for (let i = reduceLabels.length - 1; i >= 0; i--)
586
+ if (reduceLabels[i]!.target === flow) return reduceLabels[i]!.antecedents!;
587
+ return flow.antecedents!;
588
+ }
589
+
590
+ // ---- Assignments and calls
591
+
592
+ function getTypeAtFlowAssignment(c: Checker, f: FlowState, flow: FlowNode): Type | undefined {
593
+ const node = flow.node!;
594
+ if (isMatchingReference(c, f.reference, node)) {
595
+ if (!isReachableFlowNode(c, flow)) return complete(f, c.unreachableNeverType);
596
+ if (getAssignmentTargetKind(node) === AssignmentKind.Compound) {
597
+ const flowType = getTypeAtFlowNode(c, f, flow.antecedent!);
598
+ return newFlowType(c, f, getBaseTypeOfLiteralType(c, flowType), f.incomplete);
599
+ }
600
+ if (f.declaredType === c.autoType || f.declaredType === c.autoArrayType) {
601
+ if (isEmptyArrayAssignment(node)) return complete(f, getEvolvingArrayType(c, c.neverType));
602
+ const assignedType = getWidenedLiteralType(c, getInitialOrAssignedType(c, f, flow));
603
+ return complete(f, isTypeAssignableTo(c, assignedType, f.declaredType) ? assignedType : c.anyArrayType);
604
+ }
605
+ let t = f.declaredType;
606
+ if (isInCompoundLikeAssignment(node)) t = getBaseTypeOfLiteralType(c, t);
607
+ if ((t.flags & TypeFlags.Union) !== 0)
608
+ return complete(f, getAssignmentReducedType(c, t, getInitialOrAssignedType(c, f, flow)));
609
+ return complete(f, t);
610
+ }
611
+ // An assignment to a prefix of a dotted name resets it to the declared type.
612
+ if (containsMatchingReference(c, f.reference, node)) {
613
+ if (!isReachableFlowNode(c, flow)) return complete(f, c.unreachableNeverType);
614
+ // The dotted name may be an expando property of a function expression; its flow continues
615
+ // back past the function's declaration.
616
+ if (node.kind === SyntaxKind.VariableDeclaration) {
617
+ const blockScope = getCombinedNodeFlags(node) & NodeFlags.BlockScoped;
618
+ const initializer = getInitializer(node);
619
+ if (
620
+ (isInJSFile(node) ||
621
+ blockScope === NodeFlags.Const ||
622
+ blockScope === NodeFlags.Using ||
623
+ blockScope === NodeFlags.AwaitUsing) &&
624
+ initializer !== undefined &&
625
+ (initializer.kind === SyntaxKind.FunctionExpression || initializer.kind === SyntaxKind.ArrowFunction)
626
+ )
627
+ return getTypeAtFlowNode(c, f, flow.antecedent!);
628
+ }
629
+ return complete(f, f.declaredType);
630
+ }
631
+ // `for (const _ in ref)` acts as a non-null check of `ref`.
632
+ if (node.kind === SyntaxKind.VariableDeclaration && node.parent!.parent!.kind === SyntaxKind.ForInStatement) {
633
+ const statementExpression = getExpression(node.parent!.parent!)!;
634
+ if (
635
+ isMatchingReference(c, f.reference, statementExpression) ||
636
+ optionalChainContainsReference(c, statementExpression, f.reference)
637
+ ) {
638
+ const antecedentType = getTypeAtFlowNode(c, f, flow.antecedent!);
639
+ const finalType = finalizeEvolvingArrayType(c, antecedentType);
640
+ return complete(
641
+ f,
642
+ hasTypeFacts(c, finalType, TypeFacts.IsUndefinedOrNull) ? getNonNullableType(c, finalType) : finalType,
643
+ );
644
+ }
645
+ }
646
+ return undefined;
647
+ }
648
+
649
+ function isEmptyArrayAssignment(node: Node): boolean {
650
+ if (node.kind === SyntaxKind.VariableDeclaration) {
651
+ const initializer = getInitializer(node);
652
+ return initializer !== undefined && isEmptyArrayLiteral(initializer);
653
+ }
654
+ const parent = node.parent!;
655
+ return (
656
+ node.kind !== SyntaxKind.BindingElement &&
657
+ parent.kind === SyntaxKind.BinaryExpression &&
658
+ isEmptyArrayLiteral((parent as BinaryExpression).right)
659
+ );
660
+ }
661
+
662
+ function isEmptyArrayLiteral(node: Node): boolean {
663
+ return node.kind === SyntaxKind.ArrayLiteralExpression && getElements(node)!.nodes.length === 0;
664
+ }
665
+
666
+ function getInitialOrAssignedType(c: Checker, f: FlowState, flow: FlowNode): Type {
667
+ const node = flow.node!;
668
+ const t =
669
+ node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement
670
+ ? getInitialType(c, node)
671
+ : getAssignedType(c, node);
672
+ // getNarrowableTypeForReference looks at the reference's position for these.
673
+ if (someTypeIsGenericWithUnionConstraint(c, t)) f.positional = true;
674
+ return getNarrowableTypeForReference(c, t, f.reference);
675
+ }
676
+
677
+ function getInitialType(c: Checker, node: Node): Type {
678
+ if (node.kind === SyntaxKind.VariableDeclaration) {
679
+ const initializer = getInitializer(node);
680
+ if (initializer !== undefined) return getTypeOfInitializer(c, initializer);
681
+ const statement = node.parent!.parent!;
682
+ if (statement.kind === SyntaxKind.ForInStatement) return c.stringType;
683
+ if (statement.kind === SyntaxKind.ForOfStatement) return checkRightHandSideOfForOf(c, statement);
684
+ return c.errorType;
685
+ }
686
+ return getInitialTypeOfBindingElement(c, node as BindingElement);
687
+ }
688
+
689
+ /** The type of an initializer: the type a variable was inferred from, else computed without caching. */
690
+ export function getTypeOfInitializer(c: Checker, node: Node): Type {
691
+ return c.resolvedTypes.get(node.id) ?? getTypeOfExpression(c, node);
692
+ }
693
+
694
+ function getInitialTypeOfBindingElement(c: Checker, node: BindingElement): Type {
695
+ const pattern = node.parent!;
696
+ const parentType = getInitialType(c, pattern.parent!);
697
+ let t: Type;
698
+ if (pattern.kind === SyntaxKind.ObjectBindingPattern)
699
+ t = getTypeOfDestructuredProperty(c, parentType, (node.propertyName ?? node.name)!);
700
+ else if (node.dotDotDotToken === undefined)
701
+ t = getTypeOfDestructuredArrayElement(c, parentType, getElements(pattern)!.nodes.indexOf(node));
702
+ else t = getTypeOfDestructuredSpreadExpression(c, parentType);
703
+ return getTypeWithDefault(c, t, node.initializer);
704
+ }
705
+
706
+ function getAssignedType(c: Checker, node: Node): Type {
707
+ const parent = node.parent!;
708
+ switch (parent.kind) {
709
+ case SyntaxKind.ForInStatement:
710
+ return c.stringType;
711
+ case SyntaxKind.ForOfStatement:
712
+ return checkRightHandSideOfForOf(c, parent);
713
+ case SyntaxKind.BinaryExpression:
714
+ return getAssignedTypeOfBinaryExpression(c, parent as BinaryExpression);
715
+ case SyntaxKind.DeleteExpression:
716
+ return c.undefinedType;
717
+ case SyntaxKind.ArrayLiteralExpression:
718
+ return getTypeOfDestructuredArrayElement(c, getAssignedType(c, parent), getElements(parent)!.nodes.indexOf(node));
719
+ case SyntaxKind.SpreadElement:
720
+ return getTypeOfDestructuredSpreadExpression(c, getAssignedType(c, parent.parent!));
721
+ case SyntaxKind.PropertyAssignment:
722
+ return getAssignedTypeOfPropertyAssignment(c, parent);
723
+ case SyntaxKind.ShorthandPropertyAssignment:
724
+ return getTypeWithDefault(
725
+ c,
726
+ getAssignedTypeOfPropertyAssignment(c, parent),
727
+ (parent as ShorthandPropertyAssignment).objectAssignmentInitializer,
728
+ );
729
+ }
730
+ return c.errorType;
731
+ }
732
+
733
+ function getAssignedTypeOfBinaryExpression(c: Checker, node: BinaryExpression): Type {
734
+ const parent = node.parent!;
735
+ const isDestructuringDefaultAssignment =
736
+ (parent.kind === SyntaxKind.ArrayLiteralExpression && isDestructuringAssignmentTarget(parent)) ||
737
+ (parent.kind === SyntaxKind.PropertyAssignment && isDestructuringAssignmentTarget(parent.parent!));
738
+ if (isDestructuringDefaultAssignment) return getTypeWithDefault(c, getAssignedType(c, node), node.right);
739
+ return getTypeOfExpression(c, node.right);
740
+ }
741
+
742
+ function isDestructuringAssignmentTarget(parent: Node): boolean {
743
+ const grandparent = parent.parent!;
744
+ return (
745
+ (grandparent.kind === SyntaxKind.BinaryExpression && (grandparent as BinaryExpression).left === parent) ||
746
+ (grandparent.kind === SyntaxKind.ForOfStatement && (grandparent as ForInOrOfStatement).initializer === parent)
747
+ );
748
+ }
749
+
750
+ function getAssignedTypeOfPropertyAssignment(c: Checker, node: Node): Type {
751
+ return getTypeOfDestructuredProperty(c, getAssignedType(c, node.parent!), getName(node)!);
752
+ }
753
+
754
+ function getTypeOfDestructuredArrayElement(c: Checker, t: Type, index: number): Type {
755
+ if (everyType(t, (u) => isTupleLikeType(c, u))) {
756
+ const elementType = getTupleElementType(c, t, index);
757
+ if (elementType !== undefined) return elementType;
758
+ }
759
+ return includeUndefinedInIndexSignature(
760
+ c,
761
+ checkIteratedTypeOrElementType(c, IterationUse.Destructuring, t, c.undefinedType, undefined),
762
+ );
763
+ }
764
+
765
+ function getTupleElementType(c: Checker, t: Type, index: number): Type | undefined {
766
+ const propType = getTypeOfPropertyOfType(c, t, String(index));
767
+ if (propType !== undefined) return propType;
768
+ if (everyType(t, isTupleType))
769
+ return getTupleElementTypeOutOfStartCount(c, t, index, c.noUncheckedIndexedAccess ? c.undefinedType : undefined);
770
+ return undefined;
771
+ }
772
+
773
+ function includeUndefinedInIndexSignature(c: Checker, t: Type): Type {
774
+ return c.noUncheckedIndexedAccess ? getUnionType(c, [t, c.missingType]) : t;
775
+ }
776
+
777
+ function getTypeOfDestructuredSpreadExpression(c: Checker, t: Type): Type {
778
+ return createArrayType(
779
+ c,
780
+ checkIteratedTypeOrElementType(c, IterationUse.Destructuring, t, c.undefinedType, undefined),
781
+ );
782
+ }
783
+
784
+ function getTypeOfDestructuredProperty(c: Checker, t: Type, name: Node): Type {
785
+ const nameType = getLiteralTypeFromPropertyName(c, name);
786
+ if (nameType === undefined || !isTypeUsableAsPropertyName(nameType)) return c.errorType;
787
+ const text = getPropertyNameFromType(nameType);
788
+ const propType = getTypeOfPropertyOfType(c, t, text);
789
+ if (propType !== undefined) return propType;
790
+ const indexInfo = getApplicableIndexInfoForName(c, t, text);
791
+ if (indexInfo !== undefined) return includeUndefinedInIndexSignature(c, indexInfo.valueType);
792
+ return c.errorType;
793
+ }
794
+
795
+ function getTypeWithDefault(c: Checker, t: Type, defaultExpression: Node | undefined): Type {
796
+ return defaultExpression !== undefined
797
+ ? getUnionType(c, [getNonUndefinedType(c, t), getTypeOfExpression(c, defaultExpression)])
798
+ : t;
799
+ }
800
+
801
+ /** The constituents of `declaredType` that some constituent of `assignedType` is assignable to. */
802
+ export function getAssignmentReducedType(c: Checker, declaredType: Type, assignedType: Type): Type {
803
+ if (declaredType === assignedType) return declaredType;
804
+ if ((assignedType.flags & TypeFlags.Never) !== 0) return assignedType;
805
+ const pair = cachedTypePairKey(declaredType.id, assignedType.id, 0);
806
+ const key = pair < 0 ? 'assignmentReduced' + declaredType.id + ',' + assignedType.id : '';
807
+ let result = pair < 0 ? c.cachedTypes.get(key) : c.cachedTypesByPair.get(pair);
808
+ if (result === undefined) {
809
+ const filteredType = filterType(c, declaredType, (t) => typeMaybeAssignableTo(c, assignedType, t));
810
+ let reducedType = filteredType;
811
+ if ((assignedType.flags & TypeFlags.BooleanLiteral) !== 0 && isFreshLiteralType(assignedType))
812
+ reducedType = mapType(c, filteredType, (t) => getFreshTypeOfLiteralType(c, t));
813
+ result = isTypeAssignableTo(c, assignedType, reducedType) ? reducedType : declaredType;
814
+ if (pair < 0) c.cachedTypes.set(key, result);
815
+ else c.cachedTypesByPair.set(pair, result);
816
+ }
817
+ return result;
818
+ }
819
+
820
+ function typeMaybeAssignableTo(c: Checker, source: Type, target: Type): boolean {
821
+ if ((source.flags & TypeFlags.Union) === 0) return isTypeAssignableTo(c, source, target);
822
+ for (const t of typesOf(source)) if (isTypeAssignableTo(c, t, target)) return true;
823
+ return false;
824
+ }
825
+
826
+ function getTypeAtFlowCall(c: Checker, f: FlowState, flow: FlowNode): Type | undefined {
827
+ const call = flow.node!;
828
+ const signature = getEffectsSignature(c, call);
829
+ if (signature === undefined) return undefined;
830
+ const predicate = getTypePredicateOfSignature(c, signature);
831
+ if (
832
+ predicate !== undefined &&
833
+ (predicate.kind === TypePredicateKind.AssertsThis || predicate.kind === TypePredicateKind.AssertsIdentifier)
834
+ ) {
835
+ const flowType = getTypeAtFlowNode(c, f, flow.antecedent!);
836
+ const incomplete = f.incomplete;
837
+ const t = finalizeEvolvingArrayType(c, flowType);
838
+ let narrowedType = t;
839
+ const args = getArguments(call)!.nodes;
840
+ if (predicate.type !== undefined) narrowedType = narrowTypeByTypePredicate(c, f, t, predicate, call, true);
841
+ else if (
842
+ predicate.kind === TypePredicateKind.AssertsIdentifier &&
843
+ predicate.parameterIndex >= 0 &&
844
+ predicate.parameterIndex < args.length
845
+ )
846
+ narrowedType = narrowTypeByAssertion(c, f, t, args[predicate.parameterIndex]!);
847
+ if (narrowedType === t) return newFlowType(c, f, flowType, incomplete);
848
+ return newFlowType(c, f, narrowedType, incomplete);
849
+ }
850
+ if ((getReturnTypeOfSignature(c, signature).flags & TypeFlags.Never) !== 0)
851
+ return complete(f, c.unreachableNeverType);
852
+ return undefined;
853
+ }
854
+
855
+ function narrowTypeByAssertion(c: Checker, f: FlowState, t: Type, expr: Node): Type {
856
+ const node = skipParentheses(expr);
857
+ if (node.kind === SyntaxKind.FalseKeyword) return c.unreachableNeverType;
858
+ if (node.kind === SyntaxKind.BinaryExpression) {
859
+ const binary = node as BinaryExpression;
860
+ if (binary.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken)
861
+ return narrowTypeByAssertion(c, f, narrowTypeByAssertion(c, f, t, binary.left), binary.right);
862
+ if (binary.operatorToken.kind === SyntaxKind.BarBarToken)
863
+ return getUnionType(c, [
864
+ narrowTypeByAssertion(c, f, t, binary.left),
865
+ narrowTypeByAssertion(c, f, t, binary.right),
866
+ ]);
867
+ }
868
+ return narrowType(c, f, t, node, true);
869
+ }
870
+
871
+ /** The signature of a call whose effects (type predicates, `never` returns) apply to control flow. */
872
+ export function getEffectsSignature(c: Checker, node: Node): Signature | undefined {
873
+ const links = c.nodeLinks(node);
874
+ let signature = links.effectsSignature;
875
+ if (signature === undefined) {
876
+ // Assertion calls resolve their target with getTypeOfDottedName to avoid circularities.
877
+ let funcType: Type | undefined = undefined;
878
+ if (node.kind === SyntaxKind.BinaryExpression)
879
+ funcType = getSymbolHasInstanceMethodOfObjectType(c, checkNonNullExpression(c, (node as BinaryExpression).right));
880
+ else {
881
+ const callee = getExpression(node)!;
882
+ // Assertions resolve their target without inference, to avoid circularities in flow analysis.
883
+ if (node.parent!.kind === SyntaxKind.ExpressionStatement) funcType = getTypeOfDottedName(c, callee);
884
+ else if (callee.kind !== SyntaxKind.SuperKeyword)
885
+ funcType = isOptionalChain(node)
886
+ ? checkNonNullType(c, getOptionalExpressionType(c, checkExpression(c, callee), callee), callee)
887
+ : checkNonNullExpression(c, callee);
888
+ }
889
+ const signatures = getSignaturesOfType(
890
+ c,
891
+ funcType !== undefined ? getApparentType(c, funcType) : c.unknownType,
892
+ SignatureKind.Call,
893
+ );
894
+ let candidate: Signature | undefined = undefined;
895
+ if (signatures.length === 1 && signatures[0]!.typeParameters.length === 0) candidate = signatures[0]!;
896
+ // Generic or overloaded predicates and assertions take effect through the resolved signature.
897
+ else if (someSignatureHasTypePredicateOrNeverReturnType(c, signatures))
898
+ candidate = getResolvedSignature(c, node, CheckMode.Normal);
899
+ signature =
900
+ candidate !== undefined && hasTypePredicateOrNeverReturnType(c, candidate) ? candidate : c.unknownSignature;
901
+ links.effectsSignature = signature;
902
+ }
903
+ return signature === c.unknownSignature ? undefined : signature;
904
+ }
905
+
906
+ function someSignatureHasTypePredicateOrNeverReturnType(c: Checker, signatures: readonly Signature[]): boolean {
907
+ for (const sig of signatures) if (hasTypePredicateOrNeverReturnType(c, sig)) return true;
908
+ return false;
909
+ }
910
+
911
+ function hasTypePredicateOrNeverReturnType(c: Checker, sig: Signature): boolean {
912
+ if (getTypePredicateOfSignature(c, sig) !== undefined) return true;
913
+ if (sig.declaration === undefined) return false;
914
+ const returnType = getReturnTypeFromAnnotation(c, sig.declaration);
915
+ return returnType !== undefined && (returnType.flags & TypeFlags.Never) !== 0;
916
+ }
917
+
918
+ /** The declared type of a dotted name, without inference, for assertion calls. */
919
+ function getTypeOfDottedName(c: Checker, node: Node): Type | undefined {
920
+ if ((node.flags & NodeFlags.InWithStatement) !== 0) return undefined;
921
+ switch (node.kind) {
922
+ case SyntaxKind.Identifier:
923
+ return getExplicitTypeOfSymbol(c, getExportSymbolOfValueSymbolIfExported(c, getResolvedSymbol(c, node)));
924
+ case SyntaxKind.ThisKeyword:
925
+ return getExplicitThisType(c, node);
926
+ case SyntaxKind.SuperKeyword:
927
+ return checkSuperExpression(c, node);
928
+ case SyntaxKind.PropertyAccessExpression: {
929
+ const t = getTypeOfDottedName(c, getExpression(node)!);
930
+ if (t === undefined) return undefined;
931
+ const name = (node as PropertyAccessExpression).name;
932
+ let prop: Symbol | undefined;
933
+ if (name.kind === SyntaxKind.PrivateIdentifier)
934
+ prop =
935
+ t.symbol !== undefined
936
+ ? getPropertyOfType(c, t, getSymbolNameForPrivateIdentifier(t.symbol, getText(name)))
937
+ : undefined;
938
+ else prop = getPropertyOfType(c, t, getText(name));
939
+ return prop !== undefined ? getExplicitTypeOfSymbol(c, prop) : undefined;
940
+ }
941
+ case SyntaxKind.ParenthesizedExpression:
942
+ return getTypeOfDottedName(c, getExpression(node)!);
943
+ }
944
+ return undefined;
945
+ }
946
+
947
+ function getExplicitTypeOfSymbol(c: Checker, original: Symbol): Type | undefined {
948
+ const symbol = resolveSymbol(c, original) ?? original;
949
+ if ((symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.ValueModule)) !== 0)
950
+ return getTypeOfSymbol(c, symbol);
951
+ if ((symbol.flags & (SymbolFlags.Variable | SymbolFlags.Property)) !== 0) {
952
+ if ((symbol.checkFlags & CheckFlags.Mapped) !== 0) {
953
+ const origin = c.symbolSyntheticOrigins.get(getSymbolId(symbol));
954
+ if (origin !== undefined && getExplicitTypeOfSymbol(c, origin) !== undefined) return getTypeOfSymbol(c, symbol);
955
+ }
956
+ const declaration = symbol.valueDeclaration;
957
+ if (declaration !== undefined) {
958
+ if (isDeclarationWithExplicitTypeAnnotation(declaration)) return getTypeOfSymbol(c, symbol);
959
+ // `for (const x of xs)` where `xs` has an explicit type.
960
+ if (
961
+ declaration.kind === SyntaxKind.VariableDeclaration &&
962
+ declaration.parent!.parent!.kind === SyntaxKind.ForOfStatement
963
+ ) {
964
+ const statement = declaration.parent!.parent! as ForInOrOfStatement;
965
+ const expressionType = getTypeOfDottedName(c, statement.expression);
966
+ if (expressionType !== undefined)
967
+ return checkIteratedTypeOrElementType(
968
+ c,
969
+ statement.awaitModifier !== undefined ? IterationUse.ForAwaitOf : IterationUse.ForOf,
970
+ expressionType,
971
+ c.undefinedType,
972
+ undefined,
973
+ );
974
+ }
975
+ }
976
+ }
977
+ return undefined;
978
+ }
979
+
980
+ function isDeclarationWithExplicitTypeAnnotation(node: Node): boolean {
981
+ switch (node.kind) {
982
+ case SyntaxKind.VariableDeclaration:
983
+ case SyntaxKind.PropertyDeclaration:
984
+ case SyntaxKind.PropertySignature:
985
+ case SyntaxKind.Parameter:
986
+ return getType(node) !== undefined;
987
+ case SyntaxKind.BinaryExpression: {
988
+ // An expando property assigned a function with a return type annotation.
989
+ const right = (node as BinaryExpression).right;
990
+ return isFunctionLike(right) && getType(right) !== undefined;
991
+ }
992
+ }
993
+ return false;
994
+ }
995
+
996
+ function getExplicitThisType(c: Checker, node: Node): Type | undefined {
997
+ const container = getThisContainer(node, false, false);
998
+ if (isFunctionLike(container)) {
999
+ const signature = getSignatureFromDeclaration(c, container);
1000
+ if (signature.thisParameter !== undefined) return getExplicitTypeOfSymbol(c, signature.thisParameter);
1001
+ }
1002
+ const parent = container.parent;
1003
+ if (parent !== undefined && isClassLike(parent)) {
1004
+ const symbol = getSymbolOfDeclaration(c, parent);
1005
+ if (symbol === undefined) return undefined;
1006
+ return isStatic(container)
1007
+ ? getTypeOfSymbol(c, symbol)
1008
+ : (getDeclaredTypeOfSymbol(c, symbol) as InterfaceType).thisType;
1009
+ }
1010
+ return undefined;
1011
+ }
1012
+
1013
+ // ---- Conditions
1014
+
1015
+ function getTypeAtFlowCondition(c: Checker, f: FlowState, flow: FlowNode): Type {
1016
+ const flowType = getTypeAtFlowNode(c, f, flow.antecedent!);
1017
+ const incomplete = f.incomplete;
1018
+ if ((flowType.flags & TypeFlags.Never) !== 0) return newFlowType(c, f, flowType, incomplete);
1019
+ const assumeTrue = (flow.flags & FlowFlags.TrueCondition) !== 0;
1020
+ const nonEvolvingType = finalizeEvolvingArrayType(c, flowType);
1021
+ const narrowedType = narrowType(c, f, nonEvolvingType, flow.node!, assumeTrue);
1022
+ if (narrowedType === nonEvolvingType) {
1023
+ f.incomplete = incomplete;
1024
+ return flowType;
1025
+ }
1026
+ return newFlowType(c, f, narrowedType, incomplete);
1027
+ }
1028
+
1029
+ function getTypeAtFlowBranchLabel(c: Checker, f: FlowState, antecedents: FlowNode[]): Type {
1030
+ const types: Type[] = [];
1031
+ let subtypeReduction = false;
1032
+ let seenIncomplete = false;
1033
+ let bypassFlow: FlowSwitchClause | undefined = undefined;
1034
+ for (const antecedent of antecedents) {
1035
+ if (
1036
+ bypassFlow === undefined &&
1037
+ (antecedent.flags & FlowFlags.SwitchClause) !== 0 &&
1038
+ (antecedent as FlowSwitchClause).isEmpty()
1039
+ ) {
1040
+ // The bypass branch of a possibly exhaustive switch.
1041
+ bypassFlow = antecedent as FlowSwitchClause;
1042
+ continue;
1043
+ }
1044
+ const flowType = getTypeAtFlowNode(c, f, antecedent);
1045
+ const incomplete = f.incomplete;
1046
+ if (flowType === f.declaredType && f.declaredType === f.initialType) return complete(f, flowType);
1047
+ if (!types.includes(flowType)) types.push(flowType);
1048
+ if (!isTypeSubsetOf(c, flowType, f.initialType)) subtypeReduction = true;
1049
+ if (incomplete) seenIncomplete = true;
1050
+ }
1051
+ if (bypassFlow !== undefined) {
1052
+ const flowType = getTypeAtFlowNode(c, f, bypassFlow);
1053
+ const incomplete = f.incomplete;
1054
+ if (
1055
+ (flowType.flags & TypeFlags.Never) === 0 &&
1056
+ !types.includes(flowType) &&
1057
+ !isExhaustiveSwitchStatement(c, bypassFlow.switchStatement)
1058
+ ) {
1059
+ if (flowType === f.declaredType && f.declaredType === f.initialType) return complete(f, flowType);
1060
+ types.push(flowType);
1061
+ if (!isTypeSubsetOf(c, flowType, f.initialType)) subtypeReduction = true;
1062
+ if (incomplete) seenIncomplete = true;
1063
+ }
1064
+ }
1065
+ return newFlowType(
1066
+ c,
1067
+ f,
1068
+ getUnionOfFlowTypes(c, f, types, subtypeReduction ? UnionReduction.Subtype : UnionReduction.Literal),
1069
+ seenIncomplete,
1070
+ );
1071
+ }
1072
+
1073
+ /**
1074
+ * The union of the types at a junction: an evolving array when every path has one, otherwise the
1075
+ * union with evolving arrays finalized.
1076
+ */
1077
+ function getUnionOfFlowTypes(c: Checker, f: FlowState, types: Type[], reduction: UnionReduction): Type {
1078
+ if (isEvolvingArrayTypeList(types)) {
1079
+ const elementTypes: Type[] = [];
1080
+ for (const t of types) elementTypes.push(getElementTypeOfEvolvingArrayType(c, t));
1081
+ return getEvolvingArrayType(c, getUnionType(c, elementTypes));
1082
+ }
1083
+ // Finalizing changes only evolving arrays; without one, the list itself is unioned (getUnionTypeEx
1084
+ // does not keep or change it).
1085
+ let finalized = types;
1086
+ for (const t of types)
1087
+ if ((t.objectFlags & ObjectFlags.EvolvingArray) !== 0) {
1088
+ finalized = [];
1089
+ for (const u of types) finalized.push(finalizeEvolvingArrayType(c, u));
1090
+ break;
1091
+ }
1092
+ const result = recombineUnknownType(c, getUnionTypeEx(c, finalized, reduction, undefined, undefined));
1093
+ const declared = f.declaredType;
1094
+ if (result !== declared && (result.flags & declared.flags & TypeFlags.Union) !== 0) {
1095
+ const a = (result as UnionType).types;
1096
+ const b = (declared as UnionType).types;
1097
+ if (a.length === b.length) {
1098
+ let same = true;
1099
+ for (let i = 0; i < a.length; i++)
1100
+ if (a[i]! !== b[i]!) {
1101
+ same = false;
1102
+ break;
1103
+ }
1104
+ if (same) return declared;
1105
+ }
1106
+ }
1107
+ return result;
1108
+ }
1109
+
1110
+ export function recombineUnknownType(c: Checker, t: Type): Type {
1111
+ return t === c.unknownUnionType ? c.unknownType : t;
1112
+ }
1113
+
1114
+ function getTypeAtFlowLoopLabel(c: Checker, f: FlowState, flow: FlowNode): Type {
1115
+ if (f.refKey === undefined) f.refKey = getFlowReferenceKey(c, f);
1116
+ if (f.refKey === '') return complete(f, f.declaredType);
1117
+ const key = f.refKey;
1118
+ let cache = c.flowLoopCaches.get(flow);
1119
+ if (cache === undefined) {
1120
+ cache = new Map<string, Type>();
1121
+ c.flowLoopCaches.set(flow, cache);
1122
+ }
1123
+ const cached = cache.get(key);
1124
+ if (cached !== undefined) return complete(f, cached);
1125
+ // A junction already being analyzed for this reference yields the types seen so far, incomplete.
1126
+ for (const loop of c.flowLoopStack) {
1127
+ if (loop.flow === flow && loop.refKey === key && loop.types.length !== 0)
1128
+ return newFlowType(c, f, getUnionOfFlowTypes(c, f, loop.types, UnionReduction.Literal), true);
1129
+ }
1130
+ const antecedentTypes: Type[] = [];
1131
+ let subtypeReduction = false;
1132
+ let firstIncomplete = false;
1133
+ let first = true;
1134
+ for (const antecedent of flow.antecedents!) {
1135
+ let flowType: Type;
1136
+ if (first) {
1137
+ // The first antecedent is the path into the loop.
1138
+ flowType = getTypeAtFlowNode(c, f, antecedent);
1139
+ firstIncomplete = f.incomplete;
1140
+ first = false;
1141
+ } else {
1142
+ c.flowLoopStack.push(new FlowLoopInfo(flow, key, antecedentTypes));
1143
+ const saveFlowTypeCache = c.flowTypeCache;
1144
+ c.flowTypeCache = undefined;
1145
+ flowType = getTypeAtFlowNode(c, f, antecedent);
1146
+ c.flowTypeCache = saveFlowTypeCache;
1147
+ c.flowLoopStack.pop();
1148
+ const restarted = cache.get(key);
1149
+ if (restarted !== undefined) return complete(f, restarted);
1150
+ }
1151
+ if (!antecedentTypes.includes(flowType)) antecedentTypes.push(flowType);
1152
+ if (!isTypeSubsetOf(c, flowType, f.initialType)) subtypeReduction = true;
1153
+ if (flowType === f.declaredType) break;
1154
+ }
1155
+ const result = getUnionOfFlowTypes(
1156
+ c,
1157
+ f,
1158
+ antecedentTypes,
1159
+ subtypeReduction ? UnionReduction.Subtype : UnionReduction.Literal,
1160
+ );
1161
+ if (firstIncomplete) return newFlowType(c, f, result, true);
1162
+ cache.set(key, result);
1163
+ return complete(f, result);
1164
+ }
1165
+
1166
+ /** A key identifying a dotted-name reference and its declared/initial types; '' when not a dotted name. */
1167
+ function getFlowReferenceKey(c: Checker, f: FlowState): string {
1168
+ return writeFlowCacheKey(c, f.reference, f.declaredType, f.initialType, f.flowContainer) ?? '';
1169
+ }
1170
+
1171
+ function writeFlowCacheKey(
1172
+ c: Checker,
1173
+ node: Node,
1174
+ declaredType: Type,
1175
+ initialType: Type,
1176
+ flowContainer: Node | undefined,
1177
+ ): string | undefined {
1178
+ switch (node.kind) {
1179
+ case SyntaxKind.Identifier:
1180
+ case SyntaxKind.ThisKeyword: {
1181
+ let key = '';
1182
+ if (node.kind === SyntaxKind.Identifier && !isThisInTypeQuery(node)) {
1183
+ const symbol = getResolvedSymbol(c, node);
1184
+ if (symbol === c.unknownSymbol) return undefined;
1185
+ key = String(getSymbolId(symbol));
1186
+ }
1187
+ key += ':' + declaredType.id;
1188
+ if (initialType !== declaredType) key += '=' + initialType.id;
1189
+ if (flowContainer !== undefined) key += '@' + getNodeId(flowContainer);
1190
+ return key;
1191
+ }
1192
+ case SyntaxKind.NonNullExpression:
1193
+ case SyntaxKind.ParenthesizedExpression:
1194
+ return writeFlowCacheKey(c, getExpression(node)!, declaredType, initialType, flowContainer);
1195
+ case SyntaxKind.QualifiedName: {
1196
+ const left = writeFlowCacheKey(c, (node as QualifiedName).left, declaredType, initialType, flowContainer);
1197
+ return left === undefined ? undefined : left + '.' + (node as QualifiedName).right.text;
1198
+ }
1199
+ case SyntaxKind.PropertyAccessExpression:
1200
+ case SyntaxKind.ElementAccessExpression: {
1201
+ const name = getAccessedPropertyName(c, node);
1202
+ if (name !== undefined) {
1203
+ const left = writeFlowCacheKey(c, getExpression(node)!, declaredType, initialType, flowContainer);
1204
+ return left === undefined ? undefined : left + '.' + name;
1205
+ }
1206
+ // `obj[key]` for a key that isn't reassigned.
1207
+ if (node.kind !== SyntaxKind.ElementAccessExpression) return undefined;
1208
+ const argument = (node as ElementAccessExpression).argumentExpression;
1209
+ if (argument.kind !== SyntaxKind.Identifier) return undefined;
1210
+ const symbol = getResolvedSymbol(c, argument);
1211
+ if (!isUnreassignedVariable(c, symbol)) return undefined;
1212
+ const left = writeFlowCacheKey(c, getExpression(node)!, declaredType, initialType, flowContainer);
1213
+ return left === undefined ? undefined : left + '.@' + getSymbolId(symbol);
1214
+ }
1215
+ // Pseudo-references of getNarrowedTypeOfSymbol.
1216
+ case SyntaxKind.ObjectBindingPattern:
1217
+ case SyntaxKind.ArrayBindingPattern:
1218
+ case SyntaxKind.FunctionDeclaration:
1219
+ case SyntaxKind.FunctionExpression:
1220
+ case SyntaxKind.ArrowFunction:
1221
+ case SyntaxKind.MethodDeclaration:
1222
+ return '#' + getNodeId(node) + '#' + declaredType.id;
1223
+ }
1224
+ return undefined;
1225
+ }
1226
+
1227
+ // ---- Narrowing by expressions
1228
+
1229
+ function narrowType(c: Checker, f: FlowState, t: Type, expr: Node, assumeTrue: boolean): Type {
1230
+ // `a?.b` implies `a` is not nullish; so does the left of `??`.
1231
+ const parent = expr.parent;
1232
+ if (
1233
+ isExpressionOfOptionalChainRoot(expr) ||
1234
+ (parent !== undefined &&
1235
+ parent.kind === SyntaxKind.BinaryExpression &&
1236
+ ((parent as BinaryExpression).operatorToken.kind === SyntaxKind.QuestionQuestionToken ||
1237
+ (parent as BinaryExpression).operatorToken.kind === SyntaxKind.QuestionQuestionEqualsToken) &&
1238
+ (parent as BinaryExpression).left === expr)
1239
+ )
1240
+ return narrowTypeByOptionality(c, f, t, expr, assumeTrue);
1241
+ switch (expr.kind) {
1242
+ case SyntaxKind.Identifier:
1243
+ // Narrowing through aliased conditions: `const ok = x !== undefined; if (ok) ...`.
1244
+ if (!isMatchingReference(c, f.reference, expr) && c.inlineLevel < 5) {
1245
+ const symbol = getResolvedSymbol(c, expr);
1246
+ if (isConstantVariable(c, symbol)) {
1247
+ const declaration = symbol.valueDeclaration;
1248
+ if (
1249
+ declaration !== undefined &&
1250
+ declaration.kind === SyntaxKind.VariableDeclaration &&
1251
+ getType(declaration) === undefined
1252
+ ) {
1253
+ const initializer = getInitializer(declaration);
1254
+ // For an access, isConstantReference reads the property symbol resolved where the
1255
+ // reference is, which narrowing of its object changes.
1256
+ if (initializer !== undefined && isAccessExpression(f.reference)) f.positional = true;
1257
+ if (initializer !== undefined && isConstantReference(c, f.reference)) {
1258
+ c.inlineLevel++;
1259
+ const result = narrowType(c, f, t, initializer, assumeTrue);
1260
+ c.inlineLevel--;
1261
+ return result;
1262
+ }
1263
+ }
1264
+ }
1265
+ }
1266
+ return narrowTypeByTruthiness(c, f, t, expr, assumeTrue);
1267
+ case SyntaxKind.ThisKeyword:
1268
+ case SyntaxKind.SuperKeyword:
1269
+ case SyntaxKind.PropertyAccessExpression:
1270
+ case SyntaxKind.ElementAccessExpression:
1271
+ return narrowTypeByTruthiness(c, f, t, expr, assumeTrue);
1272
+ case SyntaxKind.CallExpression:
1273
+ return narrowTypeByCallExpression(c, f, t, expr, assumeTrue);
1274
+ case SyntaxKind.ParenthesizedExpression:
1275
+ case SyntaxKind.NonNullExpression:
1276
+ case SyntaxKind.SatisfiesExpression:
1277
+ return narrowType(c, f, t, getExpression(expr)!, assumeTrue);
1278
+ case SyntaxKind.BinaryExpression:
1279
+ return narrowTypeByBinaryExpression(c, f, t, expr as BinaryExpression, assumeTrue);
1280
+ case SyntaxKind.PrefixUnaryExpression:
1281
+ if ((expr as PrefixUnaryExpression).operator === SyntaxKind.ExclamationToken)
1282
+ return narrowType(c, f, t, (expr as PrefixUnaryExpression).operand, !assumeTrue);
1283
+ break;
1284
+ }
1285
+ return t;
1286
+ }
1287
+
1288
+ function narrowTypeByOptionality(c: Checker, f: FlowState, t: Type, expr: Node, assumePresent: boolean): Type {
1289
+ const facts = assumePresent ? TypeFacts.NEUndefinedOrNull : TypeFacts.EQUndefinedOrNull;
1290
+ if (isMatchingReference(c, f.reference, expr)) return getAdjustedTypeWithFacts(c, t, facts);
1291
+ const access = getDiscriminantPropertyAccess(c, f, expr, t);
1292
+ if (access !== undefined) return narrowTypeByDiscriminant(c, t, access, (u) => getTypeWithFacts(c, u, facts));
1293
+ return t;
1294
+ }
1295
+
1296
+ function narrowTypeByTruthiness(c: Checker, f: FlowState, t: Type, expr: Node, assumeTrue: boolean): Type {
1297
+ const facts = assumeTrue ? TypeFacts.Truthy : TypeFacts.Falsy;
1298
+ if (isMatchingReference(c, f.reference, expr)) return getAdjustedTypeWithFacts(c, t, facts);
1299
+ if (c.strictNullChecks && assumeTrue && optionalChainContainsReference(c, expr, f.reference))
1300
+ t = getAdjustedTypeWithFacts(c, t, TypeFacts.NEUndefinedOrNull);
1301
+ const access = getDiscriminantPropertyAccess(c, f, expr, t);
1302
+ if (access !== undefined) return narrowTypeByDiscriminant(c, t, access, (u) => getTypeWithFacts(c, u, facts));
1303
+ return t;
1304
+ }
1305
+
1306
+ function narrowTypeByCallExpression(c: Checker, f: FlowState, t: Type, call: Node, assumeTrue: boolean): Type {
1307
+ if (hasMatchingArgument(c, call, f.reference)) {
1308
+ const signature = assumeTrue || !isCallChain(call) ? getEffectsSignature(c, call) : undefined;
1309
+ const predicate = signature !== undefined ? getTypePredicateOfSignature(c, signature) : undefined;
1310
+ if (
1311
+ predicate !== undefined &&
1312
+ (predicate.kind === TypePredicateKind.This || predicate.kind === TypePredicateKind.Identifier)
1313
+ )
1314
+ return narrowTypeByTypePredicate(c, f, t, predicate, call, assumeTrue);
1315
+ }
1316
+ // `obj.hasOwnProperty("p")` narrows an optional `obj.p` under exactOptionalPropertyTypes.
1317
+ if (containsMissingType(c, t) && isAccessExpression(f.reference)) {
1318
+ const callee = getExpression(call)!;
1319
+ if (callee.kind === SyntaxKind.PropertyAccessExpression) {
1320
+ const name = (callee as PropertyAccessExpression).name;
1321
+ const args = getArguments(call)!.nodes;
1322
+ if (
1323
+ isMatchingReference(c, getExpression(f.reference)!, getReferenceCandidate(getExpression(callee)!)) &&
1324
+ name.kind === SyntaxKind.Identifier &&
1325
+ getText(name) === 'hasOwnProperty' &&
1326
+ args.length === 1 &&
1327
+ isStringLiteralLike(args[0]!) &&
1328
+ getAccessedPropertyName(c, f.reference) === getText(args[0]!)
1329
+ )
1330
+ return getTypeWithFacts(c, t, assumeTrue ? TypeFacts.NEUndefined : TypeFacts.EQUndefined);
1331
+ }
1332
+ }
1333
+ return t;
1334
+ }
1335
+
1336
+ function narrowTypeByTypePredicate(
1337
+ c: Checker,
1338
+ f: FlowState,
1339
+ t: Type,
1340
+ predicate: TypePredicate,
1341
+ call: Node,
1342
+ assumeTrue: boolean,
1343
+ ): Type {
1344
+ const predicateType = predicate.type;
1345
+ if (predicateType === undefined) return t;
1346
+ if (
1347
+ (t.flags & TypeFlags.Any) !== 0 &&
1348
+ (predicateType === c.globalObjectType || predicateType === c.globalFunctionType)
1349
+ )
1350
+ return t;
1351
+ const argument = getTypePredicateArgument(predicate, call);
1352
+ if (argument === undefined) return t;
1353
+ if (isMatchingReference(c, f.reference, argument)) return getNarrowedType(c, t, predicateType, assumeTrue, false);
1354
+ if (
1355
+ c.strictNullChecks &&
1356
+ optionalChainContainsReference(c, argument, f.reference) &&
1357
+ ((assumeTrue && !hasTypeFacts(c, predicateType, TypeFacts.EQUndefined)) ||
1358
+ (!assumeTrue && everyType(predicateType, isNullableType)))
1359
+ )
1360
+ t = getAdjustedTypeWithFacts(c, t, TypeFacts.NEUndefinedOrNull);
1361
+ const access = getDiscriminantPropertyAccess(c, f, argument, t);
1362
+ if (access !== undefined)
1363
+ return narrowTypeByDiscriminant(c, t, access, (u) => getNarrowedType(c, u, predicateType, assumeTrue, false));
1364
+ return t;
1365
+ }
1366
+
1367
+ function isNullableType(t: Type): boolean {
1368
+ return (t.flags & TypeFlags.Nullable) !== 0;
1369
+ }
1370
+
1371
+ function getTypePredicateArgument(predicate: TypePredicate, call: Node): Node | undefined {
1372
+ if (predicate.kind === TypePredicateKind.Identifier || predicate.kind === TypePredicateKind.AssertsIdentifier) {
1373
+ const args = getArguments(call)!.nodes;
1374
+ return predicate.parameterIndex >= 0 && predicate.parameterIndex < args.length
1375
+ ? args[predicate.parameterIndex]!
1376
+ : undefined;
1377
+ }
1378
+ const invoked = skipParentheses(getExpression(call)!);
1379
+ return invoked.kind === SyntaxKind.PropertyAccessExpression || invoked.kind === SyntaxKind.ElementAccessExpression
1380
+ ? skipParentheses(getExpression(invoked)!)
1381
+ : undefined;
1382
+ }
1383
+
1384
+ function narrowTypeByBinaryExpression(
1385
+ c: Checker,
1386
+ f: FlowState,
1387
+ t: Type,
1388
+ expr: BinaryExpression,
1389
+ assumeTrue: boolean,
1390
+ ): Type {
1391
+ const operator = expr.operatorToken.kind;
1392
+ switch (operator) {
1393
+ case SyntaxKind.EqualsToken:
1394
+ case SyntaxKind.BarBarEqualsToken:
1395
+ case SyntaxKind.AmpersandAmpersandEqualsToken:
1396
+ case SyntaxKind.QuestionQuestionEqualsToken:
1397
+ return narrowTypeByTruthiness(c, f, narrowType(c, f, t, expr.right, assumeTrue), expr.left, assumeTrue);
1398
+ case SyntaxKind.EqualsEqualsToken:
1399
+ case SyntaxKind.ExclamationEqualsToken:
1400
+ case SyntaxKind.EqualsEqualsEqualsToken:
1401
+ case SyntaxKind.ExclamationEqualsEqualsToken: {
1402
+ const left = getReferenceCandidate(expr.left);
1403
+ const right = getReferenceCandidate(expr.right);
1404
+ if (left.kind === SyntaxKind.TypeOfExpression && isStringLiteralLike(right))
1405
+ return narrowTypeByTypeof(c, f, t, left, operator, right, assumeTrue);
1406
+ if (right.kind === SyntaxKind.TypeOfExpression && isStringLiteralLike(left))
1407
+ return narrowTypeByTypeof(c, f, t, right, operator, left, assumeTrue);
1408
+ if (isMatchingReference(c, f.reference, left)) return narrowTypeByEquality(c, t, operator, right, assumeTrue);
1409
+ if (isMatchingReference(c, f.reference, right)) return narrowTypeByEquality(c, t, operator, left, assumeTrue);
1410
+ if (c.strictNullChecks) {
1411
+ if (optionalChainContainsReference(c, left, f.reference))
1412
+ t = narrowTypeByOptionalChainContainment(c, t, operator, right, assumeTrue);
1413
+ else if (optionalChainContainsReference(c, right, f.reference))
1414
+ t = narrowTypeByOptionalChainContainment(c, t, operator, left, assumeTrue);
1415
+ }
1416
+ const leftAccess = getDiscriminantPropertyAccess(c, f, left, t);
1417
+ if (leftAccess !== undefined)
1418
+ return narrowTypeByDiscriminantProperty(c, t, leftAccess, operator, right, assumeTrue);
1419
+ const rightAccess = getDiscriminantPropertyAccess(c, f, right, t);
1420
+ if (rightAccess !== undefined)
1421
+ return narrowTypeByDiscriminantProperty(c, t, rightAccess, operator, left, assumeTrue);
1422
+ if (isMatchingConstructorReference(c, f, left)) return narrowTypeByConstructor(c, t, operator, right, assumeTrue);
1423
+ if (isMatchingConstructorReference(c, f, right)) return narrowTypeByConstructor(c, t, operator, left, assumeTrue);
1424
+ if (isBooleanLiteral(right) && !isAccessExpression(left))
1425
+ return narrowTypeByBooleanComparison(c, f, t, left, right, operator, assumeTrue);
1426
+ if (isBooleanLiteral(left) && !isAccessExpression(right))
1427
+ return narrowTypeByBooleanComparison(c, f, t, right, left, operator, assumeTrue);
1428
+ break;
1429
+ }
1430
+ case SyntaxKind.InstanceOfKeyword:
1431
+ return narrowTypeByInstanceof(c, f, t, expr, assumeTrue);
1432
+ case SyntaxKind.InKeyword: {
1433
+ if (expr.left.kind === SyntaxKind.PrivateIdentifier)
1434
+ return narrowTypeByPrivateIdentifierInInExpression(c, f, t, expr, assumeTrue);
1435
+ const target = getReferenceCandidate(expr.right);
1436
+ if (
1437
+ containsMissingType(c, t) &&
1438
+ isAccessExpression(f.reference) &&
1439
+ isMatchingReference(c, getExpression(f.reference)!, target)
1440
+ ) {
1441
+ const leftType = getTypeOfExpression(c, expr.left);
1442
+ if (
1443
+ isTypeUsableAsPropertyName(leftType) &&
1444
+ getAccessedPropertyName(c, f.reference) === getPropertyNameFromType(leftType)
1445
+ )
1446
+ return getTypeWithFacts(c, t, assumeTrue ? TypeFacts.NEUndefined : TypeFacts.EQUndefined);
1447
+ }
1448
+ if (isMatchingReference(c, f.reference, target)) {
1449
+ const leftType = getTypeOfExpression(c, expr.left);
1450
+ if (isTypeUsableAsPropertyName(leftType)) return narrowTypeByInKeyword(c, t, leftType, assumeTrue);
1451
+ }
1452
+ break;
1453
+ }
1454
+ case SyntaxKind.CommaToken:
1455
+ return narrowType(c, f, t, expr.right, assumeTrue);
1456
+ case SyntaxKind.AmpersandAmpersandToken:
1457
+ if (assumeTrue) return narrowType(c, f, narrowType(c, f, t, expr.left, true), expr.right, true);
1458
+ return getUnionType(c, [narrowType(c, f, t, expr.left, false), narrowType(c, f, t, expr.right, false)]);
1459
+ case SyntaxKind.BarBarToken:
1460
+ if (assumeTrue)
1461
+ return getUnionType(c, [narrowType(c, f, t, expr.left, true), narrowType(c, f, t, expr.right, true)]);
1462
+ return narrowType(c, f, narrowType(c, f, t, expr.left, false), expr.right, false);
1463
+ }
1464
+ return t;
1465
+ }
1466
+
1467
+ function narrowTypeByPrivateIdentifierInInExpression(
1468
+ c: Checker,
1469
+ f: FlowState,
1470
+ t: Type,
1471
+ expr: BinaryExpression,
1472
+ assumeTrue: boolean,
1473
+ ): Type {
1474
+ if (!isMatchingReference(c, f.reference, getReferenceCandidate(expr.right))) return t;
1475
+ const symbol = getSymbolForPrivateIdentifierExpression(c, expr.left);
1476
+ if (symbol === undefined) return t;
1477
+ const classSymbol = symbol.parent!;
1478
+ const targetType = hasStaticModifier(symbol.valueDeclaration!)
1479
+ ? getTypeOfSymbol(c, classSymbol)
1480
+ : getDeclaredTypeOfSymbol(c, classSymbol);
1481
+ return getNarrowedType(c, t, targetType, assumeTrue, true);
1482
+ }
1483
+
1484
+ function isBooleanLiteral(node: Node): boolean {
1485
+ return node.kind === SyntaxKind.TrueKeyword || node.kind === SyntaxKind.FalseKeyword;
1486
+ }
1487
+
1488
+ function isAccessExpression(node: Node): boolean {
1489
+ return node.kind === SyntaxKind.PropertyAccessExpression || node.kind === SyntaxKind.ElementAccessExpression;
1490
+ }
1491
+
1492
+ function isStringLiteralLike(node: Node): boolean {
1493
+ return node.kind === SyntaxKind.StringLiteral || node.kind === SyntaxKind.NoSubstitutionTemplateLiteral;
1494
+ }
1495
+
1496
+ function narrowTypeByBooleanComparison(
1497
+ c: Checker,
1498
+ f: FlowState,
1499
+ t: Type,
1500
+ expr: Node,
1501
+ boolValue: Node,
1502
+ operator: SyntaxKind,
1503
+ assumeTrue: boolean,
1504
+ ): Type {
1505
+ const isEquality =
1506
+ operator !== SyntaxKind.ExclamationEqualsEqualsToken && operator !== SyntaxKind.ExclamationEqualsToken;
1507
+ return narrowType(c, f, t, expr, (assumeTrue !== (boolValue.kind === SyntaxKind.TrueKeyword)) !== isEquality);
1508
+ }
1509
+
1510
+ function narrowTypeByEquality(c: Checker, t: Type, operator: SyntaxKind, value: Node, assumeTrueIn: boolean): Type {
1511
+ if ((t.flags & TypeFlags.Any) !== 0) return t;
1512
+ let assumeTrue = assumeTrueIn;
1513
+ if (operator === SyntaxKind.ExclamationEqualsToken || operator === SyntaxKind.ExclamationEqualsEqualsToken)
1514
+ assumeTrue = !assumeTrue;
1515
+ const valueType = getTypeOfExpression(c, value);
1516
+ const doubleEquals = operator === SyntaxKind.EqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsToken;
1517
+ if ((t.flags & TypeFlags.Union) === 0) return narrowTypeByEqualityWorker(c, t, valueType, doubleEquals, assumeTrue);
1518
+ // The result depends only on the types and the operator, and each flow walk through a condition
1519
+ // narrows the same union again: cache it.
1520
+ const bits = 8 | (doubleEquals ? 2 : 0) | (assumeTrue ? 1 : 0);
1521
+ const pair = cachedTypePairKey(t.id, valueType.id, bits);
1522
+ const key = pair < 0 ? 'narrowedByEquality' + t.id + ',' + valueType.id + ',' + bits : '';
1523
+ let result = pair < 0 ? c.cachedTypes.get(key) : c.cachedTypesByPair.get(pair);
1524
+ if (result === undefined) {
1525
+ result = narrowTypeByEqualityWorker(c, t, valueType, doubleEquals, assumeTrue);
1526
+ if (pair < 0) c.cachedTypes.set(key, result);
1527
+ else c.cachedTypesByPair.set(pair, result);
1528
+ }
1529
+ return result;
1530
+ }
1531
+
1532
+ function narrowTypeByEqualityWorker(
1533
+ c: Checker,
1534
+ t: Type,
1535
+ valueType: Type,
1536
+ doubleEquals: boolean,
1537
+ assumeTrue: boolean,
1538
+ ): Type {
1539
+ if ((valueType.flags & TypeFlags.Nullable) !== 0) {
1540
+ if (!c.strictNullChecks) return t;
1541
+ let facts: TypeFacts;
1542
+ if (doubleEquals) facts = assumeTrue ? TypeFacts.EQUndefinedOrNull : TypeFacts.NEUndefinedOrNull;
1543
+ else if ((valueType.flags & TypeFlags.Null) !== 0) facts = assumeTrue ? TypeFacts.EQNull : TypeFacts.NENull;
1544
+ else facts = assumeTrue ? TypeFacts.EQUndefined : TypeFacts.NEUndefined;
1545
+ return getAdjustedTypeWithFacts(c, t, facts);
1546
+ }
1547
+ if (assumeTrue) {
1548
+ if (
1549
+ !doubleEquals &&
1550
+ ((t.flags & TypeFlags.Unknown) !== 0 || someType(t, (u) => isEmptyAnonymousObjectType(c, u)))
1551
+ ) {
1552
+ if (
1553
+ (valueType.flags & (TypeFlags.Primitive | TypeFlags.NonPrimitive)) !== 0 ||
1554
+ isEmptyAnonymousObjectType(c, valueType)
1555
+ )
1556
+ return valueType;
1557
+ if ((valueType.flags & TypeFlags.Object) !== 0) return c.nonPrimitiveType;
1558
+ }
1559
+ const filtered = filterType(
1560
+ c,
1561
+ t,
1562
+ (u) => areTypesComparable(c, u, valueType) || (doubleEquals && isCoercibleUnderDoubleEquals(u, valueType)),
1563
+ );
1564
+ return replacePrimitivesWithLiterals(c, filtered, valueType);
1565
+ }
1566
+ if (isUnitType(valueType))
1567
+ return filterType(c, t, (u) => !(isUnitLikeType(u) && areTypesComparable(c, u, valueType)));
1568
+ return t;
1569
+ }
1570
+
1571
+ function isCoercibleUnderDoubleEquals(source: Type, target: Type): boolean {
1572
+ return (
1573
+ (source.flags & (TypeFlags.Number | TypeFlags.String | TypeFlags.BooleanLiteral)) !== 0 &&
1574
+ (target.flags & (TypeFlags.Number | TypeFlags.String | TypeFlags.Boolean)) !== 0
1575
+ );
1576
+ }
1577
+
1578
+ function isUnitLikeType(t: Type): boolean {
1579
+ return extractUnitType(t) !== undefined;
1580
+ }
1581
+
1582
+ /** `t`, or the first unit type of intersection `t`; undefined when `t` isn't unit-like. */
1583
+ function extractUnitType(t: Type): Type | undefined {
1584
+ if ((t.flags & TypeFlags.Intersection) === 0) return isUnitType(t) ? t : undefined;
1585
+ for (const u of typesOf(t)) if (isUnitType(u)) return u;
1586
+ return undefined;
1587
+ }
1588
+
1589
+ function replacePrimitivesWithLiterals(c: Checker, typeWithPrimitives: Type, typeWithLiterals: Type): Type {
1590
+ if (
1591
+ maybeTypeOfKind(
1592
+ typeWithPrimitives,
1593
+ TypeFlags.String | TypeFlags.TemplateLiteral | TypeFlags.Number | TypeFlags.BigInt,
1594
+ ) &&
1595
+ maybeTypeOfKind(
1596
+ typeWithLiterals,
1597
+ TypeFlags.StringLiteral |
1598
+ TypeFlags.TemplateLiteral |
1599
+ TypeFlags.StringMapping |
1600
+ TypeFlags.NumberLiteral |
1601
+ TypeFlags.BigIntLiteral,
1602
+ )
1603
+ ) {
1604
+ return mapType(c, typeWithPrimitives, (t) => {
1605
+ if ((t.flags & TypeFlags.String) !== 0)
1606
+ return extractTypesOfKind(
1607
+ c,
1608
+ typeWithLiterals,
1609
+ TypeFlags.String | TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping,
1610
+ );
1611
+ if (
1612
+ isPatternLiteralType(c, t) &&
1613
+ !maybeTypeOfKind(typeWithLiterals, TypeFlags.String | TypeFlags.TemplateLiteral | TypeFlags.StringMapping)
1614
+ )
1615
+ return extractTypesOfKind(c, typeWithLiterals, TypeFlags.StringLiteral);
1616
+ if ((t.flags & TypeFlags.Number) !== 0)
1617
+ return extractTypesOfKind(c, typeWithLiterals, TypeFlags.Number | TypeFlags.NumberLiteral);
1618
+ if ((t.flags & TypeFlags.BigInt) !== 0)
1619
+ return extractTypesOfKind(c, typeWithLiterals, TypeFlags.BigInt | TypeFlags.BigIntLiteral);
1620
+ return t;
1621
+ });
1622
+ }
1623
+ return typeWithPrimitives;
1624
+ }
1625
+
1626
+ function extractTypesOfKind(c: Checker, t: Type, kind: TypeFlags): Type {
1627
+ return filterType(c, t, (u) => (u.flags & kind) !== 0);
1628
+ }
1629
+
1630
+ function narrowTypeByTypeof(
1631
+ c: Checker,
1632
+ f: FlowState,
1633
+ t: Type,
1634
+ typeOfExpr: Node,
1635
+ operator: SyntaxKind,
1636
+ literal: Node,
1637
+ assumeTrueIn: boolean,
1638
+ ): Type {
1639
+ let assumeTrue = assumeTrueIn;
1640
+ if (operator === SyntaxKind.ExclamationEqualsToken || operator === SyntaxKind.ExclamationEqualsEqualsToken)
1641
+ assumeTrue = !assumeTrue;
1642
+ const target = getReferenceCandidate(getExpression(typeOfExpr)!);
1643
+ const text = getText(literal);
1644
+ if (!isMatchingReference(c, f.reference, target)) {
1645
+ if (
1646
+ c.strictNullChecks &&
1647
+ optionalChainContainsReference(c, target, f.reference) &&
1648
+ assumeTrue === (text !== 'undefined')
1649
+ )
1650
+ t = getAdjustedTypeWithFacts(c, t, TypeFacts.NEUndefinedOrNull);
1651
+ const access = getDiscriminantPropertyAccess(c, f, target, t);
1652
+ if (access !== undefined)
1653
+ return narrowTypeByDiscriminant(c, t, access, (u) => narrowTypeByLiteralExpression(c, u, text, assumeTrue));
1654
+ return t;
1655
+ }
1656
+ return narrowTypeByLiteralExpression(c, t, text, assumeTrue);
1657
+ }
1658
+
1659
+ function typeofNEFacts(text: string): TypeFacts {
1660
+ switch (text) {
1661
+ case 'string':
1662
+ return TypeFacts.TypeofNEString;
1663
+ case 'number':
1664
+ return TypeFacts.TypeofNENumber;
1665
+ case 'bigint':
1666
+ return TypeFacts.TypeofNEBigInt;
1667
+ case 'boolean':
1668
+ return TypeFacts.TypeofNEBoolean;
1669
+ case 'symbol':
1670
+ return TypeFacts.TypeofNESymbol;
1671
+ case 'undefined':
1672
+ return TypeFacts.NEUndefined;
1673
+ case 'object':
1674
+ return TypeFacts.TypeofNEObject;
1675
+ case 'function':
1676
+ return TypeFacts.TypeofNEFunction;
1677
+ }
1678
+ return TypeFacts.TypeofNEHostObject;
1679
+ }
1680
+
1681
+ function narrowTypeByLiteralExpression(c: Checker, t: Type, text: string, assumeTrue: boolean): Type {
1682
+ return assumeTrue ? narrowTypeByTypeName(c, t, text) : getAdjustedTypeWithFacts(c, t, typeofNEFacts(text));
1683
+ }
1684
+
1685
+ function narrowTypeByTypeName(c: Checker, t: Type, typeName: string): Type {
1686
+ switch (typeName) {
1687
+ case 'string':
1688
+ return narrowTypeByTypeFacts(c, t, c.stringType, TypeFacts.TypeofEQString);
1689
+ case 'number':
1690
+ return narrowTypeByTypeFacts(c, t, c.numberType, TypeFacts.TypeofEQNumber);
1691
+ case 'bigint':
1692
+ return narrowTypeByTypeFacts(c, t, c.bigintType, TypeFacts.TypeofEQBigInt);
1693
+ case 'boolean':
1694
+ return narrowTypeByTypeFacts(c, t, c.booleanType, TypeFacts.TypeofEQBoolean);
1695
+ case 'symbol':
1696
+ return narrowTypeByTypeFacts(c, t, c.esSymbolType, TypeFacts.TypeofEQSymbol);
1697
+ case 'object':
1698
+ if ((t.flags & TypeFlags.Any) !== 0) return t;
1699
+ return getUnionType(c, [
1700
+ narrowTypeByTypeFacts(c, t, c.nonPrimitiveType, TypeFacts.TypeofEQObject),
1701
+ narrowTypeByTypeFacts(c, t, c.nullType, TypeFacts.EQNull),
1702
+ ]);
1703
+ case 'function':
1704
+ if ((t.flags & TypeFlags.Any) !== 0) return t;
1705
+ return narrowTypeByTypeFacts(c, t, c.globalFunctionType, TypeFacts.TypeofEQFunction);
1706
+ case 'undefined':
1707
+ return narrowTypeByTypeFacts(c, t, c.undefinedType, TypeFacts.EQUndefined);
1708
+ }
1709
+ return narrowTypeByTypeFacts(c, t, c.nonPrimitiveType, TypeFacts.TypeofEQHostObject);
1710
+ }
1711
+
1712
+ function narrowTypeByTypeFacts(c: Checker, t: Type, impliedType: Type, facts: TypeFacts): Type {
1713
+ return mapType(c, t, (u) => {
1714
+ if (isTypeRelatedTo(c, u, impliedType, c.strictSubtypeRelation)) return hasTypeFacts(c, u, facts) ? u : c.neverType;
1715
+ if (isTypeSubtypeOf(c, impliedType, u)) return impliedType;
1716
+ if (hasTypeFacts(c, u, facts)) return getIntersectionType(c, [u, impliedType]);
1717
+ return c.neverType;
1718
+ });
1719
+ }
1720
+
1721
+ function narrowTypeByOptionalChainContainment(
1722
+ c: Checker,
1723
+ t: Type,
1724
+ operator: SyntaxKind,
1725
+ value: Node,
1726
+ assumeTrue: boolean,
1727
+ ): Type {
1728
+ const equalsOperator = operator === SyntaxKind.EqualsEqualsToken || operator === SyntaxKind.EqualsEqualsEqualsToken;
1729
+ const nullableFlags =
1730
+ operator === SyntaxKind.EqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsToken
1731
+ ? TypeFlags.Nullable
1732
+ : TypeFlags.Undefined;
1733
+ const valueType = getTypeOfExpression(c, value);
1734
+ const removeNullable =
1735
+ (equalsOperator !== assumeTrue && everyType(valueType, (u) => (u.flags & nullableFlags) !== 0)) ||
1736
+ (equalsOperator === assumeTrue &&
1737
+ everyType(valueType, (u) => (u.flags & (TypeFlags.AnyOrUnknown | nullableFlags)) === 0));
1738
+ return removeNullable ? getAdjustedTypeWithFacts(c, t, TypeFacts.NEUndefinedOrNull) : t;
1739
+ }
1740
+
1741
+ function narrowTypeByInstanceof(c: Checker, f: FlowState, t: Type, expr: BinaryExpression, assumeTrue: boolean): Type {
1742
+ const left = getReferenceCandidate(expr.left);
1743
+ if (!isMatchingReference(c, f.reference, left)) {
1744
+ if (assumeTrue && c.strictNullChecks && optionalChainContainsReference(c, left, f.reference))
1745
+ return getAdjustedTypeWithFacts(c, t, TypeFacts.NEUndefinedOrNull);
1746
+ return t;
1747
+ }
1748
+ const rightType = getTypeOfExpression(c, expr.right);
1749
+ if (!isTypeDerivedFrom(c, rightType, c.globalObjectType)) return t;
1750
+ // A `[Symbol.hasInstance]` method with a type predicate narrows like a type guard call.
1751
+ const signature = getEffectsSignature(c, expr);
1752
+ const predicate = signature !== undefined ? getTypePredicateOfSignature(c, signature) : undefined;
1753
+ if (predicate !== undefined && predicate.kind === TypePredicateKind.Identifier && predicate.parameterIndex === 0)
1754
+ return getNarrowedType(c, t, predicate.type!, assumeTrue, true);
1755
+ if (!isTypeDerivedFrom(c, rightType, c.globalFunctionType)) return t;
1756
+ const instanceType = mapType(c, rightType, (u) => getInstanceType(c, u));
1757
+ if (
1758
+ ((t.flags & TypeFlags.Any) !== 0 &&
1759
+ (instanceType === c.globalObjectType || instanceType === c.globalFunctionType)) ||
1760
+ (!assumeTrue && !((instanceType.flags & TypeFlags.Object) !== 0 && !isEmptyAnonymousObjectType(c, instanceType)))
1761
+ )
1762
+ return t;
1763
+ return getNarrowedType(c, t, instanceType, assumeTrue, true);
1764
+ }
1765
+
1766
+ function getInstanceType(c: Checker, constructorType: Type): Type {
1767
+ const prototypeType = getTypeOfPropertyOfType(c, constructorType, 'prototype');
1768
+ if (prototypeType !== undefined && (prototypeType.flags & TypeFlags.Any) === 0) return prototypeType;
1769
+ const signatures = getSignaturesOfType(c, constructorType, SignatureKind.Construct);
1770
+ if (signatures.length === 0) return c.emptyObjectType;
1771
+ const types: Type[] = [];
1772
+ for (const s of signatures) types.push(getReturnTypeOfSignature(c, getErasedSignature(c, s)));
1773
+ return getUnionType(c, types);
1774
+ }
1775
+
1776
+ function narrowTypeByInKeyword(c: Checker, t: Type, nameType: Type, assumeTrue: boolean): Type {
1777
+ const name = getPropertyNameFromType(nameType);
1778
+ if (someType(t, (u) => isTypePresencePossible(c, u, name, true)))
1779
+ return filterType(c, t, (u) => isTypePresencePossible(c, u, name, assumeTrue));
1780
+ // `"x" in t` for an unknown property x narrows t to `t & Record<"x", unknown>`.
1781
+ if (assumeTrue) {
1782
+ const record = getGlobalTypeAliasSymbol(c, 'Record', 2, true);
1783
+ if (record !== undefined)
1784
+ return getIntersectionType(c, [t, getTypeAliasInstantiation(c, record, [nameType, c.unknownType], undefined)]);
1785
+ }
1786
+ return t;
1787
+ }
1788
+
1789
+ function isTypePresencePossible(c: Checker, t: Type, propName: string, assumeTrue: boolean): boolean {
1790
+ const prop = getPropertyOfType(c, t, propName);
1791
+ if (prop !== undefined)
1792
+ return (prop.flags & SymbolFlags.Optional) !== 0 || (prop.checkFlags & CheckFlags.Partial) !== 0 || assumeTrue;
1793
+ return getApplicableIndexInfoForName(c, t, propName) !== undefined || !assumeTrue;
1794
+ }
1795
+
1796
+ /** `t` narrowed to `candidate` (or with it removed when `assumeTrue` is false). */
1797
+ export function getNarrowedType(
1798
+ c: Checker,
1799
+ t: Type,
1800
+ candidate: Type,
1801
+ assumeTrue: boolean,
1802
+ checkDerived: boolean,
1803
+ ): Type {
1804
+ if ((t.flags & TypeFlags.Union) === 0) return getNarrowedTypeWorker(c, t, candidate, assumeTrue, checkDerived);
1805
+ const pair = cachedTypePairKey(t.id, candidate.id, 4 | (assumeTrue ? 2 : 0) | (checkDerived ? 1 : 0));
1806
+ const key =
1807
+ pair < 0 ? 'narrowed' + t.id + ',' + candidate.id + (assumeTrue ? 't' : 'f') + (checkDerived ? 'd' : '') : '';
1808
+ let result = pair < 0 ? c.cachedTypes.get(key) : c.cachedTypesByPair.get(pair);
1809
+ if (result === undefined) {
1810
+ result = getNarrowedTypeWorker(c, t, candidate, assumeTrue, checkDerived);
1811
+ if (pair < 0) c.cachedTypes.set(key, result);
1812
+ else c.cachedTypesByPair.set(pair, result);
1813
+ }
1814
+ return result;
1815
+ }
1816
+
1817
+ function getNarrowedTypeWorker(
1818
+ c: Checker,
1819
+ typeIn: Type,
1820
+ candidate: Type,
1821
+ assumeTrue: boolean,
1822
+ checkDerived: boolean,
1823
+ ): Type {
1824
+ let t = typeIn;
1825
+ if (!assumeTrue) {
1826
+ if (t === candidate) return c.neverType;
1827
+ if (checkDerived) return filterType(c, t, (u) => !isTypeDerivedFrom(c, u, candidate));
1828
+ if ((t.flags & TypeFlags.Unknown) !== 0) t = c.unknownUnionType;
1829
+ const trueType = getNarrowedType(c, t, candidate, true, false);
1830
+ return recombineUnknownType(
1831
+ c,
1832
+ filterType(c, t, (u) => !isTypeSubsetOf(c, u, trueType)),
1833
+ );
1834
+ }
1835
+ if ((t.flags & TypeFlags.AnyOrUnknown) !== 0) return candidate;
1836
+ if (t === candidate) return candidate;
1837
+ const keyPropertyName = (t.flags & TypeFlags.Union) !== 0 ? getKeyPropertyName(c, t as UnionType) : '';
1838
+ const narrowedType = mapType(c, candidate, (n) => {
1839
+ let matching = t;
1840
+ if (keyPropertyName !== '') {
1841
+ const discriminant = getTypeOfPropertyOfType(c, n, keyPropertyName);
1842
+ if (discriminant !== undefined) {
1843
+ const constituent = getConstituentTypeForKeyType(c, t as UnionType, discriminant);
1844
+ if (constituent !== undefined) matching = constituent;
1845
+ }
1846
+ }
1847
+ const directlyRelated = mapType(c, matching, (u) => {
1848
+ if (checkDerived) {
1849
+ if (isTypeDerivedFrom(c, u, n)) return u;
1850
+ if (isTypeDerivedFrom(c, n, u)) return n;
1851
+ return c.neverType;
1852
+ }
1853
+ if (isTypeStrictSubtypeOf(c, u, n)) return u;
1854
+ if (isTypeStrictSubtypeOf(c, n, u)) return n;
1855
+ if (isTypeSubtypeOf(c, u, n)) return u;
1856
+ if (isTypeSubtypeOf(c, n, u)) return n;
1857
+ return c.neverType;
1858
+ });
1859
+ if ((directlyRelated.flags & TypeFlags.Never) === 0) return directlyRelated;
1860
+ return mapType(c, t, (u) => {
1861
+ if (maybeTypeOfKind(u, TypeFlags.Instantiable)) {
1862
+ const constraint = getBaseConstraintOfType(c, u);
1863
+ if (
1864
+ constraint === undefined ||
1865
+ (checkDerived ? isTypeDerivedFrom(c, n, constraint) : isTypeSubtypeOf(c, n, constraint))
1866
+ )
1867
+ return getIntersectionType(c, [u, n]);
1868
+ }
1869
+ return c.neverType;
1870
+ });
1871
+ });
1872
+ if ((narrowedType.flags & TypeFlags.Never) === 0) return narrowedType;
1873
+ if (isTypeSubtypeOf(c, candidate, t)) return candidate;
1874
+ if (isTypeAssignableTo(c, t, candidate)) return t;
1875
+ if (isTypeAssignableTo(c, candidate, t)) return candidate;
1876
+ return getIntersectionType(c, [t, candidate]);
1877
+ }
1878
+
1879
+ // ---- Discriminants
1880
+
1881
+ function getDiscriminantPropertyAccess(c: Checker, f: FlowState, expr: Node, computedType: Type): Node | undefined {
1882
+ if ((f.declaredType.flags & TypeFlags.Union) === 0 && (computedType.flags & TypeFlags.Union) === 0) return undefined;
1883
+ const access = getCandidateDiscriminantPropertyAccess(c, f, expr);
1884
+ if (access === undefined) return undefined;
1885
+ const name = getAccessedPropertyName(c, access);
1886
+ if (name === undefined) return undefined;
1887
+ const t =
1888
+ (f.declaredType.flags & TypeFlags.Union) !== 0 && isTypeSubsetOf(c, computedType, f.declaredType)
1889
+ ? f.declaredType
1890
+ : computedType;
1891
+ return isDiscriminantProperty(c, t, name) ? access : undefined;
1892
+ }
1893
+
1894
+ function getCandidateDiscriminantPropertyAccess(c: Checker, f: FlowState, expr: Node): Node | undefined {
1895
+ const reference = f.reference;
1896
+ if (
1897
+ reference.kind === SyntaxKind.ObjectBindingPattern ||
1898
+ reference.kind === SyntaxKind.ArrayBindingPattern ||
1899
+ reference.kind === SyntaxKind.FunctionExpression ||
1900
+ reference.kind === SyntaxKind.ArrowFunction ||
1901
+ isObjectLiteralMethod(reference)
1902
+ ) {
1903
+ // A pseudo-reference from getNarrowedTypeOfSymbol: a sibling destructured variable or parameter is a candidate.
1904
+ if (expr.kind !== SyntaxKind.Identifier) return undefined;
1905
+ const declaration = getExportSymbolOfValueSymbolIfExported(c, getResolvedSymbol(c, expr)).valueDeclaration;
1906
+ if (
1907
+ declaration !== undefined &&
1908
+ (declaration.kind === SyntaxKind.BindingElement || declaration.kind === SyntaxKind.Parameter) &&
1909
+ declaration.parent === reference &&
1910
+ getInitializer(declaration) === undefined &&
1911
+ (declaration.kind === SyntaxKind.BindingElement
1912
+ ? (declaration as BindingElement).dotDotDotToken
1913
+ : getDotDotDotToken(declaration)) === undefined
1914
+ )
1915
+ return declaration;
1916
+ return undefined;
1917
+ }
1918
+ if (isAccessExpression(expr)) return isMatchingReference(c, reference, getExpression(expr)!) ? expr : undefined;
1919
+ if (expr.kind === SyntaxKind.Identifier) {
1920
+ const symbol = getResolvedSymbol(c, expr);
1921
+ if (isConstantVariable(c, symbol)) {
1922
+ const declaration = symbol.valueDeclaration;
1923
+ // `const x = obj.kind` makes `x` an alias of `obj.kind`.
1924
+ const initializer = getCandidateVariableDeclarationInitializer(declaration);
1925
+ if (
1926
+ initializer !== undefined &&
1927
+ isAccessExpression(initializer) &&
1928
+ isMatchingReference(c, reference, getExpression(initializer)!)
1929
+ )
1930
+ return initializer;
1931
+ // `const { kind: x } = obj` makes `x` an alias of `obj.kind`.
1932
+ if (
1933
+ declaration !== undefined &&
1934
+ declaration.kind === SyntaxKind.BindingElement &&
1935
+ getInitializer(declaration) === undefined
1936
+ ) {
1937
+ const parentInitializer = getCandidateVariableDeclarationInitializer(declaration.parent!.parent!);
1938
+ if (
1939
+ parentInitializer !== undefined &&
1940
+ (parentInitializer.kind === SyntaxKind.Identifier || isAccessExpression(parentInitializer)) &&
1941
+ isMatchingReference(c, reference, parentInitializer)
1942
+ )
1943
+ return declaration;
1944
+ }
1945
+ }
1946
+ }
1947
+ return undefined;
1948
+ }
1949
+
1950
+ function getCandidateVariableDeclarationInitializer(node: Node | undefined): Node | undefined {
1951
+ if (node === undefined || node.kind !== SyntaxKind.VariableDeclaration || getType(node) !== undefined)
1952
+ return undefined;
1953
+ const initializer = getInitializer(node);
1954
+ return initializer !== undefined ? skipParentheses(initializer) : undefined;
1955
+ }
1956
+
1957
+ function narrowTypeByDiscriminant(c: Checker, t: Type, access: Node, narrow: (t: Type) => Type): Type {
1958
+ const propName = getAccessedPropertyName(c, access);
1959
+ if (propName === undefined) return t;
1960
+ const optionalChain = isOptionalChain(access);
1961
+ const removeNullable =
1962
+ c.strictNullChecks && (optionalChain || isNonNullAccess(access)) && maybeTypeOfKind(t, TypeFlags.Nullable);
1963
+ const nonNullType = removeNullable ? getTypeWithFacts(c, t, TypeFacts.NEUndefinedOrNull) : t;
1964
+ let propType = getTypeOfPropertyOfType(c, nonNullType, propName);
1965
+ if (propType === undefined) return t;
1966
+ if (removeNullable && optionalChain) propType = getOptionalType(c, propType, false);
1967
+ const narrowedPropType = narrow(propType);
1968
+ return filterType(c, t, (u) => {
1969
+ const discriminantType = getTypeOfPropertyOrIndexSignatureOfType(c, u, propName) ?? c.unknownType;
1970
+ return (
1971
+ (discriminantType.flags & TypeFlags.Never) === 0 &&
1972
+ (narrowedPropType.flags & TypeFlags.Never) === 0 &&
1973
+ areTypesComparable(c, narrowedPropType, discriminantType)
1974
+ );
1975
+ });
1976
+ }
1977
+
1978
+ function isNonNullAccess(node: Node): boolean {
1979
+ return isAccessExpression(node) && getExpression(node)!.kind === SyntaxKind.NonNullExpression;
1980
+ }
1981
+
1982
+ function getTypeOfPropertyOrIndexSignatureOfType(c: Checker, t: Type, name: string): Type | undefined {
1983
+ const propType = getTypeOfPropertyOfType(c, t, name);
1984
+ if (propType !== undefined) return propType;
1985
+ const info = getApplicableIndexInfoForName(c, t, name);
1986
+ return info !== undefined ? getOptionalType(c, info.valueType, true) : undefined;
1987
+ }
1988
+
1989
+ function narrowTypeByDiscriminantProperty(
1990
+ c: Checker,
1991
+ t: Type,
1992
+ access: Node,
1993
+ operator: SyntaxKind,
1994
+ value: Node,
1995
+ assumeTrue: boolean,
1996
+ ): Type {
1997
+ if (
1998
+ (operator === SyntaxKind.EqualsEqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsEqualsToken) &&
1999
+ (t.flags & TypeFlags.Union) !== 0
2000
+ ) {
2001
+ const keyPropertyName = getKeyPropertyName(c, t as UnionType);
2002
+ if (keyPropertyName !== '' && keyPropertyName === getAccessedPropertyName(c, access)) {
2003
+ const candidate = getConstituentTypeForKeyType(c, t as UnionType, getTypeOfExpression(c, value));
2004
+ if (candidate !== undefined) {
2005
+ if (
2006
+ (assumeTrue && operator === SyntaxKind.EqualsEqualsEqualsToken) ||
2007
+ (!assumeTrue && operator === SyntaxKind.ExclamationEqualsEqualsToken)
2008
+ )
2009
+ return candidate;
2010
+ const propType = getTypeOfPropertyOfType(c, candidate, keyPropertyName);
2011
+ return propType !== undefined && isUnitType(propType) ? removeType(c, t, candidate) : t;
2012
+ }
2013
+ }
2014
+ }
2015
+ return narrowTypeByDiscriminant(c, t, access, (u) => narrowTypeByEquality(c, u, operator, value, assumeTrue));
2016
+ }
2017
+
2018
+ /** The name of a property usable to index the constituents of a large union by literal values, or ''. */
2019
+ export function getKeyPropertyName(c: Checker, t: UnionType): string {
2020
+ const side = sideOf(c, t);
2021
+ if (side.keyPropertyName === '') computeKeyPropertyNameAndMap(c, t, side);
2022
+ return side.keyPropertyName === InternalSymbolName.Missing ? '' : side.keyPropertyName;
2023
+ }
2024
+
2025
+ export function getConstituentTypeForKeyType(c: Checker, t: UnionType, keyType: Type): Type | undefined {
2026
+ const result = sideOf(c, t).constituentMap?.get(getRegularTypeOfLiteralType(c, keyType));
2027
+ return result !== c.unknownType ? result : undefined;
2028
+ }
2029
+
2030
+ /** Computes the key property of `t` and its constituents by key into `side`, the holder of its state. */
2031
+ function computeKeyPropertyNameAndMap(c: Checker, t: UnionType, side: UnionType): void {
2032
+ side.keyPropertyName = InternalSymbolName.Missing;
2033
+ const types = t.types;
2034
+ let objectCount = 0;
2035
+ for (const u of types) if ((u.flags & (TypeFlags.Object | TypeFlags.InstantiableNonPrimitive)) !== 0) objectCount++;
2036
+ if (types.length < 10 || (t.objectFlags & ObjectFlags.PrimitiveUnion) !== 0 || objectCount < 10) return;
2037
+ let keyPropertyName = '';
2038
+ for (const u of types) {
2039
+ if (keyPropertyName !== '') break;
2040
+ if ((u.flags & (TypeFlags.Object | TypeFlags.InstantiableNonPrimitive)) === 0) continue;
2041
+ for (const p of getPropertiesOfType(c, u)) {
2042
+ if (isUnitType(getTypeOfSymbol(c, p))) {
2043
+ keyPropertyName = p.name;
2044
+ break;
2045
+ }
2046
+ }
2047
+ }
2048
+ if (keyPropertyName === '') return;
2049
+ const map = new Map<Type, Type>();
2050
+ let count = 0;
2051
+ for (const u of types) {
2052
+ if ((u.flags & (TypeFlags.Object | TypeFlags.Intersection | TypeFlags.InstantiableNonPrimitive)) === 0) continue;
2053
+ const discriminant = getTypeOfPropertyOfType(c, u, keyPropertyName);
2054
+ if (discriminant === undefined || !isLiteralType(discriminant)) return;
2055
+ let duplicate = false;
2056
+ for (const d of (discriminant.flags & TypeFlags.Union) !== 0 ? typesOf(discriminant) : [discriminant]) {
2057
+ const key = getRegularTypeOfLiteralType(c, d);
2058
+ const existing = map.get(key);
2059
+ if (existing === undefined) map.set(key, u);
2060
+ else if (existing !== c.unknownType) {
2061
+ map.set(key, c.unknownType);
2062
+ duplicate = true;
2063
+ }
2064
+ }
2065
+ if (!duplicate) count++;
2066
+ }
2067
+ if (count >= 10 && count * 2 >= types.length) {
2068
+ side.keyPropertyName = keyPropertyName;
2069
+ side.constituentMap = map;
2070
+ }
2071
+ }
2072
+
2073
+ // ---- Switch statements
2074
+
2075
+ function getTypeAtSwitchClause(c: Checker, f: FlowState, flow: FlowSwitchClause): Type {
2076
+ const statement = flow.switchStatement as SwitchStatement;
2077
+ const expr = skipParentheses(statement.expression);
2078
+ const flowType = getTypeAtFlowNode(c, f, flow.antecedent!);
2079
+ const incomplete = f.incomplete;
2080
+ let t = flowType;
2081
+ if (isMatchingReference(c, f.reference, expr)) t = narrowTypeBySwitchOnDiscriminant(c, t, flow);
2082
+ else if (expr.kind === SyntaxKind.TypeOfExpression && isMatchingReference(c, f.reference, getExpression(expr)!))
2083
+ t = narrowTypeBySwitchOnTypeOf(c, t, flow);
2084
+ else if (expr.kind === SyntaxKind.TrueKeyword) t = narrowTypeBySwitchOnTrue(c, f, t, flow);
2085
+ else {
2086
+ if (c.strictNullChecks) {
2087
+ if (optionalChainContainsReference(c, expr, f.reference))
2088
+ t = narrowTypeBySwitchOptionalChainContainment(
2089
+ c,
2090
+ t,
2091
+ flow,
2092
+ (u) => (u.flags & (TypeFlags.Undefined | TypeFlags.Never)) === 0,
2093
+ );
2094
+ else if (
2095
+ expr.kind === SyntaxKind.TypeOfExpression &&
2096
+ optionalChainContainsReference(c, getExpression(expr)!, f.reference)
2097
+ )
2098
+ t = narrowTypeBySwitchOptionalChainContainment(
2099
+ c,
2100
+ t,
2101
+ flow,
2102
+ (u) =>
2103
+ !(
2104
+ (u.flags & TypeFlags.Never) !== 0 ||
2105
+ ((u.flags & TypeFlags.StringLiteral) !== 0 && (u as LiteralType).stringValue === 'undefined')
2106
+ ),
2107
+ );
2108
+ }
2109
+ const access = getDiscriminantPropertyAccess(c, f, expr, t);
2110
+ if (access !== undefined) t = narrowTypeBySwitchOnDiscriminantProperty(c, t, access, flow);
2111
+ }
2112
+ return newFlowType(c, f, t, incomplete);
2113
+ }
2114
+
2115
+ function narrowTypeBySwitchOptionalChainContainment(
2116
+ c: Checker,
2117
+ t: Type,
2118
+ flow: FlowSwitchClause,
2119
+ clauseCheck: (t: Type) => boolean,
2120
+ ): Type {
2121
+ if (flow.clauseStart === flow.clauseEnd) return t;
2122
+ const clauseTypes = getSwitchClauseTypes(c, flow.switchStatement);
2123
+ for (let i = flow.clauseStart; i < flow.clauseEnd; i++) if (!clauseCheck(clauseTypes[i])) return t;
2124
+ return getTypeWithFacts(c, t, TypeFacts.NEUndefinedOrNull);
2125
+ }
2126
+
2127
+ function narrowTypeBySwitchOnDiscriminantProperty(c: Checker, t: Type, access: Node, flow: FlowSwitchClause): Type {
2128
+ if (flow.clauseStart < flow.clauseEnd && (t.flags & TypeFlags.Union) !== 0) {
2129
+ const accessedName = getAccessedPropertyName(c, access);
2130
+ if (accessedName !== undefined && accessedName !== '' && getKeyPropertyName(c, t as UnionType) === accessedName) {
2131
+ const clauseTypes = getSwitchClauseTypes(c, flow.switchStatement);
2132
+ const types: Type[] = [];
2133
+ for (let i = flow.clauseStart; i < flow.clauseEnd && i < clauseTypes.length; i++)
2134
+ types.push(getConstituentTypeForKeyType(c, t as UnionType, clauseTypes[i]!) ?? c.unknownType);
2135
+ const candidate = getUnionType(c, types);
2136
+ if (candidate !== c.unknownType) return candidate;
2137
+ }
2138
+ }
2139
+ return narrowTypeByDiscriminant(c, t, access, (u) => narrowTypeBySwitchOnDiscriminant(c, u, flow));
2140
+ }
2141
+
2142
+ function getClauses(statement: Node): Node[] {
2143
+ return (statement as SwitchStatement).caseBlock.clauses.nodes;
2144
+ }
2145
+
2146
+ function getSwitchClauseTypes(c: Checker, statement: Node): Type[] {
2147
+ const links = c.nodeLinks(statement);
2148
+ if (links.switchTypes === undefined) {
2149
+ const types: Type[] = [];
2150
+ for (const clause of getClauses(statement)) {
2151
+ const expr = (clause as CaseOrDefaultClause).expression;
2152
+ types.push(expr !== undefined ? getRegularTypeOfLiteralType(c, getTypeOfExpression(c, expr)) : c.neverType);
2153
+ }
2154
+ links.switchTypes = types;
2155
+ }
2156
+ return links.switchTypes;
2157
+ }
2158
+
2159
+ function narrowTypeBySwitchOnDiscriminant(c: Checker, t: Type, flow: FlowSwitchClause): Type {
2160
+ if ((t.flags & TypeFlags.Union) === 0) return narrowTypeBySwitchOnDiscriminantWorker(c, t, flow);
2161
+ // As in narrowTypeByEquality, each union is narrowed by each range of clauses once.
2162
+ const key =
2163
+ 'narrowedBySwitch' + t.id + ',' + getNodeId(flow.switchStatement) + ',' + flow.clauseStart + ',' + flow.clauseEnd;
2164
+ let result = c.cachedTypes.get(key);
2165
+ if (result === undefined) {
2166
+ result = narrowTypeBySwitchOnDiscriminantWorker(c, t, flow);
2167
+ c.cachedTypes.set(key, result);
2168
+ }
2169
+ return result;
2170
+ }
2171
+
2172
+ function narrowTypeBySwitchOnDiscriminantWorker(c: Checker, t: Type, flow: FlowSwitchClause): Type {
2173
+ const switchTypes = getSwitchClauseTypes(c, flow.switchStatement);
2174
+ if (switchTypes.length === 0) return t;
2175
+ const clauseTypes = switchTypes.slice(flow.clauseStart, flow.clauseEnd);
2176
+ const hasDefaultClause = flow.clauseStart === flow.clauseEnd || clauseTypes.includes(c.neverType);
2177
+ if ((t.flags & TypeFlags.Unknown) !== 0 && !hasDefaultClause) {
2178
+ const ground: Type[] = [];
2179
+ for (const s of clauseTypes) {
2180
+ if ((s.flags & (TypeFlags.Primitive | TypeFlags.NonPrimitive)) !== 0) ground.push(s);
2181
+ else if ((s.flags & TypeFlags.Object) !== 0) ground.push(c.nonPrimitiveType);
2182
+ else return t;
2183
+ }
2184
+ return getUnionType(c, ground);
2185
+ }
2186
+ const discriminantType = getUnionType(c, clauseTypes);
2187
+ const caseType =
2188
+ (discriminantType.flags & TypeFlags.Never) !== 0
2189
+ ? c.neverType
2190
+ : replacePrimitivesWithLiterals(
2191
+ c,
2192
+ filterType(c, t, (u) => areTypesComparable(c, discriminantType, u)),
2193
+ discriminantType,
2194
+ );
2195
+ if (!hasDefaultClause) return caseType;
2196
+ const defaultType = filterType(c, t, (u) => {
2197
+ const unit = extractUnitType(u);
2198
+ if (unit === undefined) return true;
2199
+ const v = (u.flags & TypeFlags.Undefined) !== 0 ? c.undefinedType : getRegularTypeOfLiteralType(c, unit);
2200
+ for (const st of switchTypes) if (isUnitType(st) && areTypesComparable(c, st, v)) return false;
2201
+ return true;
2202
+ });
2203
+ if ((caseType.flags & TypeFlags.Never) !== 0) return defaultType;
2204
+ return getUnionType(c, [caseType, defaultType]);
2205
+ }
2206
+
2207
+ function getSwitchClauseTypeOfWitnesses(c: Checker, statement: Node): string[] | undefined {
2208
+ const links = c.nodeLinks(statement);
2209
+ if (links.switchWitnesses === undefined) {
2210
+ const witnesses: string[] = [];
2211
+ let valid = true;
2212
+ for (const clause of getClauses(statement)) {
2213
+ const expr = (clause as CaseOrDefaultClause).expression;
2214
+ if (expr === undefined) {
2215
+ witnesses.push('');
2216
+ continue;
2217
+ }
2218
+ if (!isStringLiteralLike(expr)) {
2219
+ valid = false;
2220
+ break;
2221
+ }
2222
+ const text = getText(expr);
2223
+ witnesses.push(witnesses.includes(text) ? '' : text);
2224
+ }
2225
+ links.switchWitnesses = valid ? witnesses : [];
2226
+ links.switchWitnessesValid = valid;
2227
+ }
2228
+ return links.switchWitnessesValid ? links.switchWitnesses : undefined;
2229
+ }
2230
+
2231
+ function getNotEqualFactsFromTypeofSwitch(start: number, end: number, witnesses: string[]): TypeFacts {
2232
+ let facts = TypeFacts.None;
2233
+ for (let i = 0; i < witnesses.length; i++)
2234
+ if ((i < start || i >= end) && witnesses[i]! !== '') facts |= typeofNEFacts(witnesses[i]!);
2235
+ return facts;
2236
+ }
2237
+
2238
+ function getDefaultClauseIndex(statement: Node): number {
2239
+ const clauses = getClauses(statement);
2240
+ for (let i = 0; i < clauses.length; i++) if (clauses[i]!.kind === SyntaxKind.DefaultClause) return i;
2241
+ return -1;
2242
+ }
2243
+
2244
+ function narrowTypeBySwitchOnTypeOf(c: Checker, t: Type, flow: FlowSwitchClause): Type {
2245
+ const witnesses = getSwitchClauseTypeOfWitnesses(c, flow.switchStatement);
2246
+ if (witnesses === undefined) return t;
2247
+ const defaultIndex = getDefaultClauseIndex(flow.switchStatement);
2248
+ const hasDefaultClause =
2249
+ flow.clauseStart === flow.clauseEnd || (defaultIndex >= flow.clauseStart && defaultIndex < flow.clauseEnd);
2250
+ if (hasDefaultClause) {
2251
+ const notEqualFacts = getNotEqualFactsFromTypeofSwitch(flow.clauseStart, flow.clauseEnd, witnesses);
2252
+ return filterType(c, t, (u) => getTypeFacts(c, u, notEqualFacts) === notEqualFacts);
2253
+ }
2254
+ const types: Type[] = [];
2255
+ for (const text of witnesses.slice(flow.clauseStart, flow.clauseEnd))
2256
+ types.push(text !== '' ? narrowTypeByTypeName(c, t, text) : c.neverType);
2257
+ return getUnionType(c, types);
2258
+ }
2259
+
2260
+ function narrowTypeBySwitchOnTrue(c: Checker, f: FlowState, typeIn: Type, flow: FlowSwitchClause): Type {
2261
+ let t = typeIn;
2262
+ const clauses = getClauses(flow.switchStatement);
2263
+ const defaultIndex = getDefaultClauseIndex(flow.switchStatement);
2264
+ const hasDefaultClause =
2265
+ flow.clauseStart === flow.clauseEnd || (defaultIndex >= flow.clauseStart && defaultIndex < flow.clauseEnd);
2266
+ for (let i = 0; i < flow.clauseStart; i++) {
2267
+ const expr = (clauses[i]! as CaseOrDefaultClause).expression;
2268
+ if (expr !== undefined) t = narrowType(c, f, t, expr, false);
2269
+ }
2270
+ if (hasDefaultClause) {
2271
+ for (let i = flow.clauseEnd; i < clauses.length; i++) {
2272
+ const expr = (clauses[i]! as CaseOrDefaultClause).expression;
2273
+ if (expr !== undefined) t = narrowType(c, f, t, expr, false);
2274
+ }
2275
+ return t;
2276
+ }
2277
+ const types: Type[] = [];
2278
+ for (let i = flow.clauseStart; i < flow.clauseEnd; i++) {
2279
+ const expr = (clauses[i]! as CaseOrDefaultClause).expression;
2280
+ types.push(expr !== undefined ? narrowType(c, f, t, expr, true) : c.neverType);
2281
+ }
2282
+ return getUnionType(c, types);
2283
+ }
2284
+
2285
+ /** Whether every value of the switch expression is handled by a case. */
2286
+ export function isExhaustiveSwitchStatement(c: Checker, statement: Node): boolean {
2287
+ const links = c.nodeLinks(statement);
2288
+ if (links.exhaustiveState === 0) {
2289
+ links.exhaustiveState = 1;
2290
+ const exhaustive = computeExhaustiveSwitchStatement(c, statement);
2291
+ if (links.exhaustiveState === 1) links.exhaustiveState = exhaustive ? 3 : 2;
2292
+ } else if (links.exhaustiveState === 1) links.exhaustiveState = 2;
2293
+ return links.exhaustiveState === 3;
2294
+ }
2295
+
2296
+ function computeExhaustiveSwitchStatement(c: Checker, statement: Node): boolean {
2297
+ const expression = (statement as SwitchStatement).expression;
2298
+ if (expression.kind === SyntaxKind.TypeOfExpression) {
2299
+ const witnesses = getSwitchClauseTypeOfWitnesses(c, statement);
2300
+ if (witnesses === undefined) return false;
2301
+ const operandConstraint = getBaseConstraintOrType(c, checkExpressionCached(c, getExpression(expression)!));
2302
+ const notEqualFacts = getNotEqualFactsFromTypeofSwitch(0, 0, witnesses);
2303
+ if ((operandConstraint.flags & TypeFlags.AnyOrUnknown) !== 0)
2304
+ return (TypeFacts.AllTypeofNE & notEqualFacts) === TypeFacts.AllTypeofNE;
2305
+ return !someType(operandConstraint, (u) => getTypeFacts(c, u, notEqualFacts) === notEqualFacts);
2306
+ }
2307
+ const t = getBaseConstraintOrType(c, checkExpressionCached(c, expression));
2308
+ if (!isLiteralType(t)) return false;
2309
+ const switchTypes = getSwitchClauseTypes(c, statement);
2310
+ if (switchTypes.length === 0) return false;
2311
+ for (const s of switchTypes) if (!isUnitType(s) && (s.flags & TypeFlags.Never) === 0) return false;
2312
+ const regular = mapType(c, t, (u) => getRegularTypeOfLiteralType(c, u));
2313
+ if ((regular.flags & TypeFlags.Union) !== 0) return typesOf(regular).every((u) => switchTypes.includes(u));
2314
+ return switchTypes.includes(regular);
2315
+ }
2316
+
2317
+ function getBaseConstraintOrType(c: Checker, t: Type): Type {
2318
+ return getBaseConstraintOfType(c, t) ?? t;
2319
+ }
2320
+
2321
+ // ---- References
2322
+
2323
+ export function isMatchingReference(c: Checker, source: Node, target: Node): boolean {
2324
+ // A declaration's symbol has the declaration's name, and an identifier's text is its name: an
2325
+ // identifier never refers to the variable or binding element of a declaration of another name.
2326
+ if (
2327
+ source.kind === SyntaxKind.Identifier &&
2328
+ (target.kind === SyntaxKind.VariableDeclaration || target.kind === SyntaxKind.BindingElement)
2329
+ ) {
2330
+ // A cast to one class: a union of the two would be boxed in native builds.
2331
+ const name =
2332
+ target.kind === SyntaxKind.VariableDeclaration
2333
+ ? (target as VariableDeclaration).name
2334
+ : (target as BindingElement).name;
2335
+ if (
2336
+ name !== undefined &&
2337
+ name.kind === SyntaxKind.Identifier &&
2338
+ (name as Identifier).text !== (source as Identifier).text
2339
+ )
2340
+ return false;
2341
+ }
2342
+ switch (target.kind) {
2343
+ case SyntaxKind.ParenthesizedExpression:
2344
+ case SyntaxKind.NonNullExpression:
2345
+ return isMatchingReference(c, source, getExpression(target)!);
2346
+ case SyntaxKind.BinaryExpression: {
2347
+ const binary = target as BinaryExpression;
2348
+ return (
2349
+ (isAssignmentExpression(target, false) && isMatchingReference(c, source, binary.left)) ||
2350
+ (binary.operatorToken.kind === SyntaxKind.CommaToken && isMatchingReference(c, source, binary.right))
2351
+ );
2352
+ }
2353
+ }
2354
+ switch (source.kind) {
2355
+ case SyntaxKind.Identifier:
2356
+ case SyntaxKind.PrivateIdentifier:
2357
+ if (isThisInTypeQuery(source)) return target.kind === SyntaxKind.ThisKeyword;
2358
+ if (target.kind === SyntaxKind.Identifier) return getResolvedSymbol(c, source) === getResolvedSymbol(c, target);
2359
+ if (target.kind === SyntaxKind.VariableDeclaration || target.kind === SyntaxKind.BindingElement)
2360
+ return (
2361
+ getExportSymbolOfValueSymbolIfExported(c, getResolvedSymbol(c, source)) === getSymbolOfDeclaration(c, target)
2362
+ );
2363
+ return false;
2364
+ case SyntaxKind.ThisKeyword:
2365
+ return target.kind === SyntaxKind.ThisKeyword;
2366
+ case SyntaxKind.SuperKeyword:
2367
+ return target.kind === SyntaxKind.SuperKeyword;
2368
+ case SyntaxKind.MetaProperty:
2369
+ return (
2370
+ target.kind === SyntaxKind.MetaProperty &&
2371
+ (source as MetaProperty).keywordToken === (target as MetaProperty).keywordToken &&
2372
+ (source as MetaProperty).name.text === (target as MetaProperty).name.text
2373
+ );
2374
+ case SyntaxKind.NonNullExpression:
2375
+ case SyntaxKind.ParenthesizedExpression:
2376
+ case SyntaxKind.SatisfiesExpression:
2377
+ return isMatchingReference(c, getExpression(source)!, target);
2378
+ case SyntaxKind.PropertyAccessExpression:
2379
+ case SyntaxKind.ElementAccessExpression: {
2380
+ const sourceName = getAccessedPropertyName(c, source);
2381
+ if (sourceName !== undefined && isAccessExpression(target)) {
2382
+ const targetName = getAccessedPropertyName(c, target);
2383
+ if (targetName !== undefined)
2384
+ return targetName === sourceName && isMatchingReference(c, getExpression(source)!, getExpression(target)!);
2385
+ }
2386
+ // `obj[key]` matches `obj[key]` for a key that isn't reassigned.
2387
+ if (source.kind === SyntaxKind.ElementAccessExpression && target.kind === SyntaxKind.ElementAccessExpression) {
2388
+ const sourceArg = (source as ElementAccessExpression).argumentExpression;
2389
+ const targetArg = (target as ElementAccessExpression).argumentExpression;
2390
+ if (sourceArg.kind === SyntaxKind.Identifier && targetArg.kind === SyntaxKind.Identifier) {
2391
+ const symbol = getResolvedSymbol(c, sourceArg);
2392
+ if (symbol === getResolvedSymbol(c, targetArg) && isUnreassignedVariable(c, symbol))
2393
+ return isMatchingReference(c, getExpression(source)!, getExpression(target)!);
2394
+ }
2395
+ }
2396
+ return false;
2397
+ }
2398
+ case SyntaxKind.QualifiedName:
2399
+ if (isAccessExpression(target)) {
2400
+ const targetName = getAccessedPropertyName(c, target);
2401
+ if (targetName !== undefined)
2402
+ return (
2403
+ (source as QualifiedName).right.text === targetName &&
2404
+ isMatchingReference(c, (source as QualifiedName).left, getExpression(target)!)
2405
+ );
2406
+ }
2407
+ return false;
2408
+ case SyntaxKind.BinaryExpression:
2409
+ return (
2410
+ (source as BinaryExpression).operatorToken.kind === SyntaxKind.CommaToken &&
2411
+ isMatchingReference(c, (source as BinaryExpression).right, target)
2412
+ );
2413
+ }
2414
+ return false;
2415
+ }
2416
+
2417
+ /** Whether `expr` is `reference.constructor`. */
2418
+ function isMatchingConstructorReference(c: Checker, f: FlowState, expr: Node): boolean {
2419
+ return (
2420
+ isAccessExpression(expr) &&
2421
+ getAccessedPropertyName(c, expr) === 'constructor' &&
2422
+ isMatchingReference(c, f.reference, getExpression(expr)!)
2423
+ );
2424
+ }
2425
+
2426
+ /** Narrows by `x.constructor === C` to the constituents constructed by `C`. */
2427
+ function narrowTypeByConstructor(
2428
+ c: Checker,
2429
+ t: Type,
2430
+ operator: SyntaxKind,
2431
+ identifier: Node,
2432
+ assumeTrue: boolean,
2433
+ ): Type {
2434
+ // Inequality doesn't narrow.
2435
+ if (
2436
+ assumeTrue
2437
+ ? operator !== SyntaxKind.EqualsEqualsToken && operator !== SyntaxKind.EqualsEqualsEqualsToken
2438
+ : operator !== SyntaxKind.ExclamationEqualsToken && operator !== SyntaxKind.ExclamationEqualsEqualsToken
2439
+ )
2440
+ return t;
2441
+ const identifierType = getTypeOfExpression(c, identifier);
2442
+ if (
2443
+ !(
2444
+ (identifierType.flags & TypeFlags.Object) !== 0 &&
2445
+ getSignaturesOfType(c, identifierType, SignatureKind.Call).length > 0
2446
+ ) &&
2447
+ !isConstructorType(c, identifierType)
2448
+ )
2449
+ return t;
2450
+ const prototypeProperty = getPropertyOfType(c, identifierType, 'prototype');
2451
+ if (prototypeProperty === undefined) return t;
2452
+ const prototypeType = getTypeOfSymbol(c, prototypeProperty);
2453
+ if (
2454
+ (prototypeType.flags & TypeFlags.Any) !== 0 ||
2455
+ prototypeType === c.globalObjectType ||
2456
+ prototypeType === c.globalFunctionType
2457
+ )
2458
+ return t;
2459
+ if ((t.flags & TypeFlags.Any) !== 0) return prototypeType;
2460
+ return filterType(c, t, (u) => isConstructedBy(c, u, prototypeType));
2461
+ }
2462
+
2463
+ function isConstructedBy(c: Checker, source: Type, target: Type): boolean {
2464
+ // Class instances are only constructed by their own class, even when structurally identical to another.
2465
+ if (
2466
+ ((source.flags & TypeFlags.Object) !== 0 && (source.objectFlags & ObjectFlags.Class) !== 0) ||
2467
+ ((target.flags & TypeFlags.Object) !== 0 && (target.objectFlags & ObjectFlags.Class) !== 0)
2468
+ )
2469
+ return source.symbol === target.symbol;
2470
+ return isTypeSubtypeOf(c, source, target);
2471
+ }
2472
+
2473
+ export function getAccessedPropertyName(c: Checker, access: Node): string | undefined {
2474
+ if (access.kind === SyntaxKind.PropertyAccessExpression) return getText((access as PropertyAccessExpression).name);
2475
+ if (access.kind === SyntaxKind.BindingElement) return getDestructuringPropertyName(c, access);
2476
+ if (access.kind === SyntaxKind.ElementAccessExpression) {
2477
+ const argument = (access as ElementAccessExpression).argumentExpression;
2478
+ if (isStringLiteralLike(argument)) return getText(argument);
2479
+ if (argument.kind === SyntaxKind.NumericLiteral) return String(Number(getText(argument)));
2480
+ if (isEntityNameExpression(argument, false)) return tryGetNameFromEntityNameExpression(c, argument);
2481
+ }
2482
+ if (access.kind === SyntaxKind.Parameter) return String(getParameters(access.parent!)!.nodes.indexOf(access));
2483
+ return undefined;
2484
+ }
2485
+
2486
+ /** The property name a constant or enum member used as an index stands for. */
2487
+ export function tryGetNameFromEntityNameExpression(c: Checker, node: Node): string | undefined {
2488
+ const symbol = resolveEntityName(c, node, SymbolFlags.Value, true, false, undefined);
2489
+ if (symbol === undefined || !(isConstantVariable(c, symbol) || (symbol.flags & SymbolFlags.EnumMember) !== 0))
2490
+ return undefined;
2491
+ const declaration = symbol.valueDeclaration;
2492
+ if (declaration === undefined) return undefined;
2493
+ const typeNode = getType(declaration);
2494
+ if (typeNode !== undefined) {
2495
+ const name = tryGetNameFromType(getTypeFromTypeNode(c, typeNode));
2496
+ if (name !== undefined) return name;
2497
+ }
2498
+ // Binding elements are excluded: their initializers don't alone determine their types, and resolving
2499
+ // their full types can be circular.
2500
+ if (
2501
+ (declaration.kind === SyntaxKind.VariableDeclaration ||
2502
+ declaration.kind === SyntaxKind.PropertyDeclaration ||
2503
+ declaration.kind === SyntaxKind.PropertyAssignment ||
2504
+ declaration.kind === SyntaxKind.Parameter ||
2505
+ declaration.kind === SyntaxKind.EnumMember) &&
2506
+ isBlockScopedNameDeclaredBeforeUse(c, declaration, node)
2507
+ ) {
2508
+ const initializer = getInitializer(declaration);
2509
+ if (initializer !== undefined) return tryGetNameFromType(getTypeOfExpression(c, initializer));
2510
+ if (declaration.kind === SyntaxKind.EnumMember) {
2511
+ const name = getName(declaration)!;
2512
+ if (isStringLiteralLike(name) || name.kind === SyntaxKind.NumericLiteral || name.kind === SyntaxKind.Identifier)
2513
+ return getText(name);
2514
+ }
2515
+ }
2516
+ return undefined;
2517
+ }
2518
+
2519
+ export function tryGetNameFromType(t: Type): string | undefined {
2520
+ return (t.flags & (TypeFlags.UniqueESSymbol | TypeFlags.StringOrNumberLiteral)) !== 0
2521
+ ? getPropertyNameFromType(t)
2522
+ : undefined;
2523
+ }
2524
+
2525
+ /** The property name or element index a destructuring element reads. */
2526
+ export function getDestructuringPropertyName(c: Checker, node: Node): string | undefined {
2527
+ const parent = node.parent!;
2528
+ let name: Node | undefined;
2529
+ if (node.kind === SyntaxKind.BindingElement && parent.kind === SyntaxKind.ObjectBindingPattern)
2530
+ name = (node as BindingElement).propertyName ?? (node as BindingElement).name;
2531
+ else if (node.kind === SyntaxKind.PropertyAssignment || node.kind === SyntaxKind.ShorthandPropertyAssignment)
2532
+ name = getName(node);
2533
+ else if (parent.kind === SyntaxKind.ArrayLiteralExpression || parent.kind === SyntaxKind.ArrayBindingPattern)
2534
+ return String(getElements(parent)!.nodes.indexOf(node));
2535
+ if (name === undefined) return undefined;
2536
+ const t = getLiteralTypeFromPropertyName(c, name);
2537
+ return t !== undefined && (t.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral)) !== 0
2538
+ ? getPropertyNameFromType(t)
2539
+ : undefined;
2540
+ }
2541
+
2542
+ export function isConstantReference(c: Checker, node: Node): boolean {
2543
+ switch (node.kind) {
2544
+ case SyntaxKind.ThisKeyword:
2545
+ return true;
2546
+ case SyntaxKind.Identifier: {
2547
+ if (isThisInTypeQuery(node)) return false;
2548
+ const symbol = getResolvedSymbol(c, node);
2549
+ return (
2550
+ isConstantVariable(c, symbol) ||
2551
+ (isParameterOrMutableLocalVariable(c, symbol) && !isSymbolAssigned(c, symbol)) ||
2552
+ (symbol.valueDeclaration !== undefined && symbol.valueDeclaration.kind === SyntaxKind.FunctionExpression)
2553
+ );
2554
+ }
2555
+ case SyntaxKind.PropertyAccessExpression:
2556
+ case SyntaxKind.ElementAccessExpression: {
2557
+ if (!isConstantReference(c, getExpression(node)!)) return false;
2558
+ const symbol = c.resolvedSymbols.get(node.id);
2559
+ return symbol !== undefined && isReadonlySymbol(c, symbol);
2560
+ }
2561
+ case SyntaxKind.ObjectBindingPattern:
2562
+ case SyntaxKind.ArrayBindingPattern: {
2563
+ // A destructuring pseudo-reference is constant when none of its variables are reassigned.
2564
+ const rootDeclaration = getRootDeclaration(node.parent!);
2565
+ if (
2566
+ rootDeclaration.kind === SyntaxKind.Parameter ||
2567
+ (rootDeclaration.kind === SyntaxKind.VariableDeclaration &&
2568
+ rootDeclaration.parent!.kind === SyntaxKind.CatchClause)
2569
+ )
2570
+ return !isSomeSymbolAssigned(c, getName(rootDeclaration)!);
2571
+ if (rootDeclaration.kind !== SyntaxKind.VariableDeclaration) return false;
2572
+ const blockScopeKind = getCombinedNodeFlags(rootDeclaration) & NodeFlags.BlockScoped;
2573
+ return (
2574
+ blockScopeKind === NodeFlags.Const ||
2575
+ blockScopeKind === NodeFlags.Using ||
2576
+ blockScopeKind === NodeFlags.AwaitUsing
2577
+ );
2578
+ }
2579
+ }
2580
+ return false;
2581
+ }
2582
+
2583
+ function containsMatchingReference(c: Checker, sourceIn: Node, target: Node): boolean {
2584
+ let source = sourceIn;
2585
+ while (isAccessExpression(source)) {
2586
+ source = getExpression(source)!;
2587
+ if (isMatchingReference(c, source, target)) return true;
2588
+ }
2589
+ return false;
2590
+ }
2591
+
2592
+ function optionalChainContainsReference(c: Checker, sourceIn: Node, target: Node): boolean {
2593
+ let source = sourceIn;
2594
+ while (isOptionalChain(source)) {
2595
+ source = getExpression(source)!;
2596
+ if (isMatchingReference(c, source, target)) return true;
2597
+ }
2598
+ return false;
2599
+ }
2600
+
2601
+ function getReferenceCandidate(node: Node): Node {
2602
+ switch (node.kind) {
2603
+ case SyntaxKind.ParenthesizedExpression:
2604
+ return getReferenceCandidate(getExpression(node)!);
2605
+ case SyntaxKind.BinaryExpression: {
2606
+ const binary = node as BinaryExpression;
2607
+ switch (binary.operatorToken.kind) {
2608
+ case SyntaxKind.EqualsToken:
2609
+ case SyntaxKind.BarBarEqualsToken:
2610
+ case SyntaxKind.AmpersandAmpersandEqualsToken:
2611
+ case SyntaxKind.QuestionQuestionEqualsToken:
2612
+ return getReferenceCandidate(binary.left);
2613
+ case SyntaxKind.CommaToken:
2614
+ return getReferenceCandidate(binary.right);
2615
+ }
2616
+ }
2617
+ }
2618
+ return node;
2619
+ }
2620
+
2621
+ export function hasMatchingArgument(c: Checker, call: Node, reference: Node): boolean {
2622
+ const args = getArguments(call);
2623
+ if (args !== undefined) {
2624
+ for (const argument of args.nodes)
2625
+ if (
2626
+ isOrContainsMatchingReference(c, reference, argument) ||
2627
+ optionalChainContainsReference(c, argument, reference)
2628
+ )
2629
+ return true;
2630
+ }
2631
+ const callee = getExpression(call)!;
2632
+ return (
2633
+ callee.kind === SyntaxKind.PropertyAccessExpression &&
2634
+ isOrContainsMatchingReference(c, reference, getExpression(callee)!)
2635
+ );
2636
+ }
2637
+
2638
+ function isOrContainsMatchingReference(c: Checker, source: Node, target: Node): boolean {
2639
+ return isMatchingReference(c, source, target) || containsMatchingReference(c, source, target);
2640
+ }
2641
+
2642
+ function isCallChain(node: Node): boolean {
2643
+ return node.kind === SyntaxKind.CallExpression && isOptionalChain(node);
2644
+ }
2645
+
2646
+ // ---- Reachability
2647
+
2648
+ export function isReachableFlowNode(c: Checker, flow: FlowNode): boolean {
2649
+ const result = isReachableFlowNodeWorker(c, flow, false);
2650
+ c.lastFlowNode = flow;
2651
+ c.lastFlowNodeReachable = result;
2652
+ return result;
2653
+ }
2654
+
2655
+ function isReachableFlowNodeWorker(c: Checker, start: FlowNode, noCacheCheckIn: boolean): boolean {
2656
+ let flow = start;
2657
+ let noCacheCheck = noCacheCheckIn;
2658
+ for (;;) {
2659
+ if (flow === c.lastFlowNode) return c.lastFlowNodeReachable;
2660
+ const flags = flow.flags;
2661
+ if ((flags & FlowFlags.Shared) !== 0) {
2662
+ if (!noCacheCheck) {
2663
+ const cached = c.flowNodeReachable.get(flow);
2664
+ if (cached !== undefined) return cached;
2665
+ const reachable = isReachableFlowNodeWorker(c, flow, true);
2666
+ c.flowNodeReachable.set(flow, reachable);
2667
+ return reachable;
2668
+ }
2669
+ noCacheCheck = false;
2670
+ }
2671
+ if ((flags & (FlowFlags.Assignment | FlowFlags.Condition | FlowFlags.ArrayMutation)) !== 0) flow = flow.antecedent!;
2672
+ else if ((flags & FlowFlags.Call) !== 0) {
2673
+ const signature = getEffectsSignature(c, flow.node!);
2674
+ if (signature !== undefined) {
2675
+ const predicate = getTypePredicateOfSignature(c, signature);
2676
+ if (
2677
+ predicate !== undefined &&
2678
+ predicate.kind === TypePredicateKind.AssertsIdentifier &&
2679
+ predicate.type === undefined
2680
+ ) {
2681
+ const args = getArguments(flow.node!)!.nodes;
2682
+ if (
2683
+ predicate.parameterIndex >= 0 &&
2684
+ predicate.parameterIndex < args.length &&
2685
+ isFalseExpression(args[predicate.parameterIndex]!)
2686
+ )
2687
+ return false;
2688
+ }
2689
+ if ((getReturnTypeOfSignature(c, signature).flags & TypeFlags.Never) !== 0) return false;
2690
+ }
2691
+ flow = flow.antecedent!;
2692
+ } else if ((flags & FlowFlags.BranchLabel) !== 0) {
2693
+ for (const antecedent of getBranchLabelAntecedents(c, flow))
2694
+ if (isReachableFlowNodeWorker(c, antecedent, false)) return true;
2695
+ return false;
2696
+ } else if ((flags & FlowFlags.LoopLabel) !== 0) {
2697
+ const antecedents = flow.antecedents;
2698
+ if (antecedents === undefined || antecedents.length === 0) return false;
2699
+ flow = antecedents[0]!;
2700
+ } else if ((flags & FlowFlags.SwitchClause) !== 0) {
2701
+ const clause = flow as FlowSwitchClause;
2702
+ if (clause.isEmpty() && isExhaustiveSwitchStatement(c, clause.switchStatement)) return false;
2703
+ flow = flow.antecedent!;
2704
+ } else if ((flags & FlowFlags.ReduceLabel) !== 0) {
2705
+ c.lastFlowNode = undefined;
2706
+ c.flowReduceLabels.push(flow as FlowReduceLabel);
2707
+ const result = isReachableFlowNodeWorker(c, flow.antecedent!, false);
2708
+ c.flowReduceLabels.pop();
2709
+ return result;
2710
+ } else return (flags & FlowFlags.Unreachable) === 0;
2711
+ }
2712
+ }
2713
+
2714
+ function isFalseExpression(expr: Node): boolean {
2715
+ const node = skipParentheses(expr);
2716
+ if (node.kind === SyntaxKind.FalseKeyword) return true;
2717
+ if (node.kind === SyntaxKind.BinaryExpression) {
2718
+ const binary = node as BinaryExpression;
2719
+ if (binary.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken)
2720
+ return isFalseExpression(binary.left) || isFalseExpression(binary.right);
2721
+ if (binary.operatorToken.kind === SyntaxKind.BarBarToken)
2722
+ return isFalseExpression(binary.left) && isFalseExpression(binary.right);
2723
+ }
2724
+ return false;
2725
+ }
2726
+
2727
+ // ---- Variables and assignments
2728
+
2729
+ export const enum AssignmentKind {
2730
+ None = 0,
2731
+ Definite = 1,
2732
+ Compound = 2,
2733
+ }
2734
+
2735
+ export function getAssignmentTargetKind(node: Node): AssignmentKind {
2736
+ const target = getAssignmentTarget(node);
2737
+ if (target === undefined) return AssignmentKind.None;
2738
+ if (target.kind === SyntaxKind.BinaryExpression) {
2739
+ const op = (target as BinaryExpression).operatorToken.kind;
2740
+ return op === SyntaxKind.EqualsToken || isLogicalOrCoalescingAssignmentOperator(op)
2741
+ ? AssignmentKind.Definite
2742
+ : AssignmentKind.Compound;
2743
+ }
2744
+ if (target.kind === SyntaxKind.PrefixUnaryExpression || target.kind === SyntaxKind.PostfixUnaryExpression)
2745
+ return AssignmentKind.Compound;
2746
+ return AssignmentKind.Definite;
2747
+ }
2748
+
2749
+ export function isInCompoundLikeAssignment(node: Node): boolean {
2750
+ const target = getAssignmentTarget(node);
2751
+ if (target === undefined || !isAssignmentExpression(target, true)) return false;
2752
+ const right = skipParentheses((target as BinaryExpression).right);
2753
+ return (
2754
+ right.kind === SyntaxKind.BinaryExpression &&
2755
+ isShiftOperatorOrHigher((right as BinaryExpression).operatorToken.kind)
2756
+ );
2757
+ }
2758
+
2759
+ function isShiftOperatorOrHigher(kind: SyntaxKind): boolean {
2760
+ switch (kind) {
2761
+ case SyntaxKind.LessThanLessThanToken:
2762
+ case SyntaxKind.GreaterThanGreaterThanToken:
2763
+ case SyntaxKind.GreaterThanGreaterThanGreaterThanToken:
2764
+ case SyntaxKind.AsteriskToken:
2765
+ case SyntaxKind.SlashToken:
2766
+ case SyntaxKind.PercentToken:
2767
+ case SyntaxKind.PlusToken:
2768
+ case SyntaxKind.MinusToken:
2769
+ case SyntaxKind.AsteriskAsteriskToken:
2770
+ return true;
2771
+ }
2772
+ return false;
2773
+ }
2774
+
2775
+ function isUnreassignedVariable(c: Checker, symbol: Symbol): boolean {
2776
+ return (
2777
+ isConstantVariable(c, symbol) || (isParameterOrMutableLocalVariable(c, symbol) && !isSymbolAssigned(c, symbol))
2778
+ );
2779
+ }
2780
+
2781
+ export function isConstantVariable(_c: Checker, symbol: Symbol): boolean {
2782
+ if ((symbol.flags & SymbolFlags.Variable) === 0 || symbol.valueDeclaration === undefined) return false;
2783
+ return (getCombinedNodeFlags(symbol.valueDeclaration) & NodeFlags.Constant) !== 0;
2784
+ }
2785
+
2786
+ export function isParameterOrMutableLocalVariable(_c: Checker, symbol: Symbol): boolean {
2787
+ if (symbol.valueDeclaration === undefined) return false;
2788
+ const declaration = getRootDeclaration(symbol.valueDeclaration);
2789
+ return (
2790
+ declaration.kind === SyntaxKind.Parameter ||
2791
+ (declaration.kind === SyntaxKind.VariableDeclaration &&
2792
+ (declaration.parent!.kind === SyntaxKind.CatchClause || isMutableLocalVariableDeclaration(declaration)))
2793
+ );
2794
+ }
2795
+
2796
+ export function isMutableLocalVariableDeclaration(declaration: Node): boolean {
2797
+ const list = declaration.parent!;
2798
+ if ((list.flags & NodeFlags.Let) === 0) return false;
2799
+ if ((getCombinedModifierFlags(declaration) & ModifierFlags.Export) !== 0) return false;
2800
+ const statement = list.parent!;
2801
+ return !(statement.kind === SyntaxKind.VariableStatement && isGlobalSourceFile(statement.parent!));
2802
+ }
2803
+
2804
+ export function isSymbolAssigned(c: Checker, symbol: Symbol): boolean {
2805
+ ensureAssignmentsMarked(c, symbol);
2806
+ return c.symbolLinks(symbol).lastAssignmentPos !== 0;
2807
+ }
2808
+
2809
+ export function isSymbolAssignedDefinitely(c: Checker, symbol: Symbol): boolean {
2810
+ ensureAssignmentsMarked(c, symbol);
2811
+ return c.symbolLinks(symbol).hasDefiniteAssignment;
2812
+ }
2813
+
2814
+ /** Whether there are no assignments to `symbol`, or `location` is past the last one. */
2815
+ export function isPastLastAssignment(c: Checker, symbol: Symbol, location: Node | undefined): boolean {
2816
+ ensureAssignmentsMarked(c, symbol);
2817
+ const pos = c.symbolLinks(symbol).lastAssignmentPos;
2818
+ return pos === 0 || (location !== undefined && pos < location.pos);
2819
+ }
2820
+
2821
+ function isFunctionOrSourceFile(node: Node): boolean {
2822
+ return node.kind === SyntaxKind.SourceFile || isFunctionLike(node);
2823
+ }
2824
+
2825
+ function findFunctionOrSourceFile(node: Node | undefined): Node | undefined {
2826
+ let current = node;
2827
+ while (current !== undefined && !isFunctionOrSourceFile(current)) current = current.parent;
2828
+ return current;
2829
+ }
2830
+
2831
+ function ensureAssignmentsMarked(c: Checker, symbol: Symbol): void {
2832
+ if (c.symbolLinks(symbol).lastAssignmentPos !== 0) return;
2833
+ const parent = findFunctionOrSourceFile(symbol.valueDeclaration);
2834
+ if (parent === undefined) return;
2835
+ const links = c.nodeLinks(parent);
2836
+ if ((links.flags & NodeCheckFlags.AssignmentsMarked) !== 0) return;
2837
+ links.flags |= NodeCheckFlags.AssignmentsMarked;
2838
+ // An enclosing function already marked everything inside it.
2839
+ let outer = parent.parent;
2840
+ while (outer !== undefined) {
2841
+ if (
2842
+ isFunctionOrSourceFile(outer) &&
2843
+ ((c.existingNodeLinks(outer)?.flags ?? 0) & NodeCheckFlags.AssignmentsMarked) !== 0
2844
+ )
2845
+ return;
2846
+ outer = outer.parent;
2847
+ }
2848
+ c.assignmentMarker.visitNode(parent);
2849
+ }
2850
+
2851
+ const maxAssignmentPos = 2147483647;
2852
+
2853
+ /** Records the last assignment position of parameters and mutable locals in one walk. */
2854
+ export class AssignmentMarker extends NodeVisitor {
2855
+ readonly c: Checker;
2856
+
2857
+ constructor(c: Checker) {
2858
+ super();
2859
+ this.c = c;
2860
+ }
2861
+
2862
+ visitNode(node: Node): boolean {
2863
+ const c = this.c;
2864
+ switch (node.kind) {
2865
+ case SyntaxKind.Identifier: {
2866
+ const kind = getAssignmentTargetKind(node);
2867
+ if (kind === AssignmentKind.None) return false;
2868
+ const symbol = getResolvedSymbol(c, node);
2869
+ if (!isParameterOrMutableLocalVariable(c, symbol)) return false;
2870
+ const links = c.symbolLinks(symbol);
2871
+ if (links.lastAssignmentPos !== maxAssignmentPos) {
2872
+ const referencing = findFunctionOrSourceFile(node);
2873
+ const declaring = findFunctionOrSourceFile(symbol.valueDeclaration);
2874
+ links.lastAssignmentPos =
2875
+ referencing === declaring ? extendAssignmentPosition(node, symbol.valueDeclaration!) : maxAssignmentPos;
2876
+ }
2877
+ if (kind === AssignmentKind.Definite) links.hasDefiniteAssignment = true;
2878
+ return false;
2879
+ }
2880
+ case SyntaxKind.ExportSpecifier: {
2881
+ const specifier = node as ExportSpecifier;
2882
+ const declaration = specifier.parent!.parent as ExportDeclaration;
2883
+ const name = specifier.propertyName ?? specifier.name;
2884
+ if (
2885
+ !specifier.isTypeOnly &&
2886
+ !declaration.isTypeOnly &&
2887
+ declaration.moduleSpecifier === undefined &&
2888
+ name.kind !== SyntaxKind.StringLiteral
2889
+ ) {
2890
+ const symbol = resolveEntityName(c, name, SymbolFlags.Value, true, true, undefined);
2891
+ if (symbol !== undefined && isParameterOrMutableLocalVariable(c, symbol))
2892
+ c.symbolLinks(symbol).lastAssignmentPos = maxAssignmentPos;
2893
+ }
2894
+ return false;
2895
+ }
2896
+ case SyntaxKind.InterfaceDeclaration:
2897
+ case SyntaxKind.TypeAliasDeclaration:
2898
+ case SyntaxKind.JSTypeAliasDeclaration:
2899
+ case SyntaxKind.EnumDeclaration:
2900
+ return false;
2901
+ }
2902
+ if (node.kind >= SyntaxKind.FirstTypeNode && node.kind <= SyntaxKind.LastTypeNode) return false;
2903
+ return node.forEachChild(this);
2904
+ }
2905
+ }
2906
+
2907
+ function extendAssignmentPosition(nodeIn: Node, declaration: Node): number {
2908
+ let node: Node | undefined = nodeIn;
2909
+ let pos = nodeIn.pos;
2910
+ while (node !== undefined && node.pos > declaration.pos) {
2911
+ switch (node.kind) {
2912
+ case SyntaxKind.VariableStatement:
2913
+ case SyntaxKind.ExpressionStatement:
2914
+ case SyntaxKind.IfStatement:
2915
+ case SyntaxKind.DoStatement:
2916
+ case SyntaxKind.WhileStatement:
2917
+ case SyntaxKind.ForStatement:
2918
+ case SyntaxKind.ForInStatement:
2919
+ case SyntaxKind.ForOfStatement:
2920
+ case SyntaxKind.WithStatement:
2921
+ case SyntaxKind.SwitchStatement:
2922
+ case SyntaxKind.TryStatement:
2923
+ case SyntaxKind.ClassDeclaration:
2924
+ pos = node.end;
2925
+ }
2926
+ node = node.parent;
2927
+ }
2928
+ return pos;
2929
+ }
2930
+
2931
+ /** The function, module block, source file or property declaration whose flow graph contains `node`. */
2932
+ export function getControlFlowContainer(node: Node): Node {
2933
+ let current = node.parent!;
2934
+ for (;;) {
2935
+ if (
2936
+ (isFunctionLike(current) && getImmediatelyInvokedFunctionExpression(current) === undefined) ||
2937
+ current.kind === SyntaxKind.ModuleBlock ||
2938
+ current.kind === SyntaxKind.SourceFile ||
2939
+ current.kind === SyntaxKind.PropertyDeclaration
2940
+ )
2941
+ return current;
2942
+ current = current.parent!;
2943
+ }
2944
+ }
2945
+
2946
+ /** Array mutations of an auto-typed array (`x.push(...)`, `x[i] = ...`) on the way to its references. */
2947
+ function getTypeAtFlowArrayMutation(c: Checker, f: FlowState, flow: FlowNode): Type | undefined {
2948
+ if (f.declaredType !== c.autoType && f.declaredType !== c.autoArrayType) return undefined;
2949
+ const node = flow.node!;
2950
+ const expr =
2951
+ node.kind === SyntaxKind.CallExpression
2952
+ ? getExpression(getExpression(node)!)!
2953
+ : getExpression((node as BinaryExpression).left)!;
2954
+ if (!isMatchingReference(c, f.reference, getReferenceCandidate(expr))) return undefined;
2955
+ const flowType = getTypeAtFlowNode(c, f, flow.antecedent!);
2956
+ if ((flowType.objectFlags & ObjectFlags.EvolvingArray) === 0) return flowType;
2957
+ const incomplete = f.incomplete;
2958
+ let evolvedType = flowType;
2959
+ if (node.kind === SyntaxKind.CallExpression) {
2960
+ for (const arg of getArguments(node)!.nodes) evolvedType = addEvolvingArrayElementType(c, evolvedType, arg);
2961
+ } else {
2962
+ // The context-free type avoids rechecking the left side without caching, which blows up.
2963
+ const binary = node as BinaryExpression;
2964
+ const indexType = getContextFreeTypeOfExpression(c, (binary.left as ElementAccessExpression).argumentExpression);
2965
+ if (isTypeAssignableToKindEx(c, indexType, TypeFlags.NumberLike, false))
2966
+ evolvedType = addEvolvingArrayElementType(c, evolvedType, binary.right);
2967
+ }
2968
+ return newFlowType(c, f, evolvedType, incomplete);
2969
+ }
2970
+
2971
+ // ---- Evolving arrays
2972
+
2973
+ /** The evolving array type of `let x = []` with the element types added so far. */
2974
+ export function getEvolvingArrayType(c: Checker, elementType: Type): Type {
2975
+ const key = cachedTypeKey(CachedTypeKind.EvolvingArray, elementType.id);
2976
+ const cached = c.cachedTypesById.get(key);
2977
+ if (cached !== undefined) return cached;
2978
+ const evolving = newObjectType(c, ObjectFlags.EvolvingArray, undefined) as EvolvingArrayType;
2979
+ evolving.elementType = elementType;
2980
+ c.cachedTypesById.set(key, evolving);
2981
+ return evolving;
2982
+ }
2983
+
2984
+ function getElementTypeOfEvolvingArrayType(c: Checker, t: Type): Type {
2985
+ return (t.objectFlags & ObjectFlags.EvolvingArray) !== 0 ? (t as EvolvingArrayType).elementType! : c.neverType;
2986
+ }
2987
+
2988
+ function isEvolvingArrayTypeList(types: readonly Type[]): boolean {
2989
+ let hasEvolvingArrayType = false;
2990
+ for (const t of types) {
2991
+ if ((t.flags & TypeFlags.Never) !== 0) continue;
2992
+ if ((t.objectFlags & ObjectFlags.EvolvingArray) === 0) return false;
2993
+ hasEvolvingArrayType = true;
2994
+ }
2995
+ return hasEvolvingArrayType;
2996
+ }
2997
+
2998
+ /**
2999
+ * Whether `node` is `x` in `x.length`, `x.push(v)`, `x.unshift(v)` or `x[n] = v` with a numeric,
3000
+ * undefined or any `n`.
3001
+ */
3002
+ export function isEvolvingArrayOperationTarget(c: Checker, node: Node): boolean {
3003
+ const root = getReferenceRoot(node);
3004
+ const parent = root.parent!;
3005
+ if (parent.kind === SyntaxKind.PropertyAccessExpression) {
3006
+ const name = (parent as PropertyAccessExpression).name;
3007
+ return (
3008
+ getText(name) === 'length' ||
3009
+ (parent.parent!.kind === SyntaxKind.CallExpression &&
3010
+ name.kind === SyntaxKind.Identifier &&
3011
+ isPushOrUnshiftIdentifier(name))
3012
+ );
3013
+ }
3014
+ if (parent.kind !== SyntaxKind.ElementAccessExpression || getExpression(parent) !== root) return false;
3015
+ const grandparent = parent.parent!;
3016
+ return (
3017
+ grandparent.kind === SyntaxKind.BinaryExpression &&
3018
+ (grandparent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken &&
3019
+ (grandparent as BinaryExpression).left === parent &&
3020
+ !isAssignmentTarget(grandparent) &&
3021
+ isTypeAssignableToKindEx(
3022
+ c,
3023
+ getTypeOfExpression(c, (parent as ElementAccessExpression).argumentExpression),
3024
+ TypeFlags.NumberLike,
3025
+ false,
3026
+ )
3027
+ );
3028
+ }
3029
+
3030
+ function getReferenceRoot(node: Node): Node {
3031
+ const parent = node.parent!;
3032
+ if (parent.kind === SyntaxKind.ParenthesizedExpression) return getReferenceRoot(parent);
3033
+ if (parent.kind === SyntaxKind.BinaryExpression) {
3034
+ const binary = parent as BinaryExpression;
3035
+ if (
3036
+ (binary.operatorToken.kind === SyntaxKind.EqualsToken && binary.left === node) ||
3037
+ (binary.operatorToken.kind === SyntaxKind.CommaToken && binary.right === node)
3038
+ )
3039
+ return getReferenceRoot(parent);
3040
+ }
3041
+ return node;
3042
+ }
3043
+
3044
+ /** Adds the type of `node` to an evolving array; subtype reduction waits until it's finalized. */
3045
+ function addEvolvingArrayElementType(c: Checker, evolvingArrayType: Type, node: Node): Type {
3046
+ const newElementType = getRegularTypeOfObjectLiteral(
3047
+ c,
3048
+ getBaseTypeOfLiteralType(c, getContextFreeTypeOfExpression(c, node)),
3049
+ );
3050
+ const elementType = (evolvingArrayType as EvolvingArrayType).elementType!;
3051
+ if (isTypeSubsetOf(c, newElementType, elementType)) return evolvingArrayType;
3052
+ return getEvolvingArrayType(c, getUnionType(c, [elementType, newElementType]));
3053
+ }
3054
+
3055
+ /** The array type an evolving array settles on; `any[]` while it has no elements. */
3056
+ export function finalizeEvolvingArrayType(c: Checker, t: Type): Type {
3057
+ if ((t.objectFlags & ObjectFlags.EvolvingArray) === 0) return t;
3058
+ const evolving = t as EvolvingArrayType;
3059
+ const side = sideOf(c, evolving);
3060
+ if (side.finalArrayType !== undefined) return side.finalArrayType;
3061
+ const elementType = evolving.elementType!;
3062
+ const finalArrayType =
3063
+ (elementType.flags & TypeFlags.Never) !== 0
3064
+ ? c.autoArrayType
3065
+ : createArrayType(
3066
+ c,
3067
+ (elementType.flags & TypeFlags.Union) !== 0
3068
+ ? getUnionTypeEx(c, (elementType as UnionType).types, UnionReduction.Subtype, undefined, undefined)
3069
+ : elementType,
3070
+ );
3071
+ side.finalArrayType = finalArrayType;
3072
+ return finalArrayType;
3073
+ }
3074
+
3075
+ /** The type of an expression checked without contextual types, computed once. */
3076
+ function getContextFreeTypeOfExpression(c: Checker, node: Node): Type {
3077
+ const links = c.nodeLinks(node);
3078
+ if (links.contextFreeType !== undefined) return links.contextFreeType;
3079
+ const t = checkExpressionEx(c, node, CheckMode.SkipContextSensitive);
3080
+ links.contextFreeType = t;
3081
+ return t;
3082
+ }
3083
+
3084
+ function reportFlowControlError(c: Checker, node: Node): void {
3085
+ let block: Node | undefined = node;
3086
+ while (block !== undefined && !isFunctionOrModuleBlock(block)) block = block.parent;
3087
+ if (block === undefined) return;
3088
+ const file = getSourceFileOfNode(node);
3089
+ const span = getRangeOfTokenAtPosition(file, getStatements(block)!.pos);
3090
+ c.addDiagnostic(
3091
+ new Diagnostic(
3092
+ file.diagnosticFile(),
3093
+ span.pos,
3094
+ span.end,
3095
+ Diagnostics.The_containing_function_or_module_body_is_too_large_for_control_flow_analysis,
3096
+ [],
3097
+ ),
3098
+ );
3099
+ }
3100
+
3101
+ function isFunctionOrModuleBlock(node: Node): boolean {
3102
+ return (
3103
+ node.kind === SyntaxKind.SourceFile ||
3104
+ node.kind === SyntaxKind.ModuleBlock ||
3105
+ (node.kind === SyntaxKind.Block && node.parent !== undefined && isFunctionLike(node.parent))
3106
+ );
3107
+ }
3108
+
3109
+ /**
3110
+ * The type of `symbol` at `location`. A destructured variable of a const declaration or unassigned
3111
+ * parameter is narrowed by checks of its siblings: in `const { kind, payload } = action`, testing
3112
+ * `kind` narrows `payload`.
3113
+ */
3114
+ export function getNarrowedTypeOfSymbol(c: Checker, symbol: Symbol, location: Node): Type {
3115
+ const t = getTypeOfSymbol(c, symbol);
3116
+ const declaration = symbol.valueDeclaration;
3117
+ if (
3118
+ declaration !== undefined &&
3119
+ declaration.kind === SyntaxKind.Parameter &&
3120
+ getType(declaration) === undefined &&
3121
+ getInitializer(declaration) === undefined &&
3122
+ getDotDotDotToken(declaration) === undefined
3123
+ )
3124
+ return getNarrowedTypeOfDependentParameter(c, t, declaration, location);
3125
+ if (
3126
+ declaration === undefined ||
3127
+ declaration.kind !== SyntaxKind.BindingElement ||
3128
+ getInitializer(declaration) !== undefined ||
3129
+ (declaration as BindingElement).dotDotDotToken !== undefined ||
3130
+ getElements(declaration.parent!)!.nodes.length < 2
3131
+ )
3132
+ return t;
3133
+ const pattern = declaration.parent!;
3134
+ const parent = pattern.parent!;
3135
+ const rootDeclaration = getRootDeclaration(parent);
3136
+ const isParameter = rootDeclaration.kind === SyntaxKind.Parameter;
3137
+ if (
3138
+ !isParameter &&
3139
+ !(
3140
+ rootDeclaration.kind === SyntaxKind.VariableDeclaration &&
3141
+ (getCombinedNodeFlags(rootDeclaration) & NodeFlags.Constant) !== 0
3142
+ )
3143
+ )
3144
+ return t;
3145
+ const links = c.nodeLinks(parent);
3146
+ if ((links.flags & NodeCheckFlags.InCheckIdentifier) !== 0) return t;
3147
+ links.flags |= NodeCheckFlags.InCheckIdentifier;
3148
+ let result = t;
3149
+ const parentType = getTypeForBindingElementParent(c, parent, CheckMode.Normal);
3150
+ const parentTypeConstraint = parentType !== undefined ? mapToBaseConstraintOrType(c, parentType) : undefined;
3151
+ if (
3152
+ parentTypeConstraint !== undefined &&
3153
+ (parentTypeConstraint.flags & TypeFlags.Union) !== 0 &&
3154
+ !(isParameter && isSomeSymbolAssigned(c, getName(rootDeclaration)!))
3155
+ ) {
3156
+ const narrowedType = getFlowTypeOfReferenceAt(
3157
+ c,
3158
+ pattern,
3159
+ parentTypeConstraint,
3160
+ parentTypeConstraint,
3161
+ undefined,
3162
+ getFlowNode(location),
3163
+ );
3164
+ // Tuple bounds aren't checked, as the narrowed parent may have fewer elements than the declared one.
3165
+ result =
3166
+ (narrowedType.flags & TypeFlags.Never) !== 0
3167
+ ? c.neverType
3168
+ : getBindingElementTypeFromParentType(c, declaration as BindingElement, narrowedType, true);
3169
+ }
3170
+ links.flags &= ~NodeCheckFlags.InCheckIdentifier;
3171
+ return result;
3172
+ }
3173
+
3174
+ /**
3175
+ * A parameter of a function contextually typed by a rest union of tuples, as in
3176
+ * `const f: (...args: [1, string] | [2, number]) => void = (kind, data) => ...`, narrowed by checks of its
3177
+ * sibling parameters: the function is the pseudo-reference for the tuple.
3178
+ */
3179
+ function getNarrowedTypeOfDependentParameter(c: Checker, t: Type, declaration: Node, location: Node): Type {
3180
+ const fn = declaration.parent!;
3181
+ const parameters = getParameters(fn)!.nodes;
3182
+ if (parameters.length < 2 || !isContextSensitiveFunctionOrObjectLiteralMethod(c, fn)) return t;
3183
+ const contextualSignature = getContextualSignature(c, fn);
3184
+ if (
3185
+ contextualSignature === undefined ||
3186
+ contextualSignature.parameters.length !== 1 ||
3187
+ !contextualSignature.hasRestParameter()
3188
+ )
3189
+ return t;
3190
+ const context = getInferenceContext(c, fn);
3191
+ const restType = getReducedApparentType(
3192
+ c,
3193
+ instantiateType(
3194
+ c,
3195
+ getTypeOfSymbol(c, contextualSignature.parameters[0]!),
3196
+ context !== undefined ? context.nonFixingMapper : undefined,
3197
+ ),
3198
+ );
3199
+ if (
3200
+ (restType.flags & TypeFlags.Union) === 0 ||
3201
+ !everyType(restType, isTupleType) ||
3202
+ someParameterAssigned(c, parameters)
3203
+ )
3204
+ return t;
3205
+ const narrowedType = getFlowTypeOfReferenceAt(c, fn, restType, restType, undefined, getFlowNode(location));
3206
+ const index = parameters.indexOf(declaration) - (isThisParameter(parameters[0]!) ? 1 : 0);
3207
+ return getIndexedAccessType(c, narrowedType, getNumberLiteralType(c, index));
3208
+ }
3209
+
3210
+ function isThisParameter(parameter: Node): boolean {
3211
+ const name = getName(parameter);
3212
+ return name !== undefined && name.kind === SyntaxKind.Identifier && getText(name) === 'this';
3213
+ }
3214
+
3215
+ function someParameterAssigned(c: Checker, parameters: Node[]): boolean {
3216
+ for (const p of parameters) if (isSomeSymbolAssigned(c, getName(p)!)) return true;
3217
+ return false;
3218
+ }
3219
+
3220
+ function isSomeSymbolAssigned(c: Checker, name: Node): boolean {
3221
+ if (name.kind === SyntaxKind.Identifier) {
3222
+ const symbol = getSymbolOfDeclaration(c, name.parent!);
3223
+ return symbol !== undefined && isSymbolAssigned(c, symbol);
3224
+ }
3225
+ for (const e of getElements(name)!.nodes) {
3226
+ const elementName = getName(e);
3227
+ if (elementName !== undefined && isSomeSymbolAssigned(c, elementName)) return true;
3228
+ }
3229
+ return false;
3230
+ }