You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Reordering variable declarations of Promise<any> and Promise<unknown> changes behaviorΒ #52100
// Reorder these twodeclareletu: Promise<unknown>declareleta: Promise<any>// Assigned an expression that is Promise<any> | Promise<unknown>// but that will undergo subtype reduction// The type of union depends on whether a or u was declared firstletunion=Math.random()>0.5
? Promise.reject<any>()
: Promise.reject<unknown>();union.then(v=>v.toString());
π Actual behavior
Reordering the unrelated variables u and a will cause the type of union to change between Promise<unknown> and Promise<any> (both in declarations and in the type of v, although tooltips still show union as Promise<any>)
Iβm thinking TS probably considers Promise<any> and Promise<unknown> to be subtypes of each other (subtyping is not a total order, from what I understand), so subtype reduction is order-dependent.
Bruce Pascoe (@fatcerberus) That is my conclusion as well. Promise<any> and Promise<unknown> are subtypes of each other. When reducing the union it matters in what order the constituents are in the union because that will determine what question is considered (Promise<any> extends Promise<unknown> and Promise<unknown> extends Promise<any>are both true ) And the order of union constituents is determined by the id of the type which is assigned in the order types are encountered.
Don't really have any solution here. Many similar issues show up.
This implies that any direct user of the checker API needs to ensure that the order of source files fed to TypeScript is deterministic and, crucially, matches the order used by tsc and the VS Code Language Service Plugin (LSP).
The file load order is a significant piece of knowledge that anyone embedding the TypeScript checker in a build tool needs to know and replicate. Otherwise the types and checking errors reported may differ between the IDE/LSP and the build tool.
Ideal Solution
Ideally, the TypeScript language would make type declaration ordering irrelevant. That is easiest for users to understand and, as a bonus, permits the most flexibility and performance. But it sounds like that is not on the table right now.
A second-best solution could be to make it possible to ban or lint-away any usage of the language that incurs ordering dependencies, so that projects could opt-into the subset of the language where ordering doesn't matter.
Fallback Solution
Today, we embed the TypeScript checker in a custom toolchain that is used locally and during a remote project publishing step. But we don't have a custom LSP - we reuse the default VS Code LSP and configure it via a generated tsconfig written to the source directory. So for true consistency, it appears that we need to update the toolchain to ensure that we are matching the canonical TypeScript file load order.
Is this canonical load order specified anywhere? Is there a way to reuse TypeScript's existing logic here? It would be great to reuse that code so that if TypeScript ever changes the order, our toolchain continues to match.
Reacted by Titian Cernicova-Dragomir, Thomas Chetwin and Ryan Cavanaugh
Ryan Cavanaugh (@RyanCavanaugh) This issue now appears to not happen anymore, and inference has stabilized on Promise<any>. This happened between 5.0.0-dev.20230210 and 5.0.0-dev.20230216 (can't pin point more accurately as playground has a gap of version between those dates)
Was this intentional? Is this going to remain so going forward?
Activity
fatcerberus commentedon Jan 4, 2023
Iβm thinking TS probably considers
Promise<any>andPromise<unknown>to be subtypes of each other (subtyping is not a total order, from what I understand), so subtype reduction is order-dependent.dragomirtitian commentedon Jan 4, 2023
Bruce Pascoe (@fatcerberus) That is my conclusion as well.
Promise<any>andPromise<unknown>are subtypes of each other. When reducing the union it matters in what order the constituents are in the union because that will determine what question is considered (Promise<any> extends Promise<unknown>andPromise<unknown> extends Promise<any>are both true ) And the order of union constituents is determined by theidof the type which is assigned in the order types are encountered.robpalme commentedon Jan 10, 2023
Given the conclusion on ordering issues in the 6th Jan Design Meeting...
This implies that any direct user of the checker API needs to ensure that the order of source files fed to TypeScript is deterministic and, crucially, matches the order used by
tscand the VS Code Language Service Plugin (LSP).The file load order is a significant piece of knowledge that anyone embedding the TypeScript checker in a build tool needs to know and replicate. Otherwise the types and checking errors reported may differ between the IDE/LSP and the build tool.
Ideal Solution
Ideally, the TypeScript language would make type declaration ordering irrelevant. That is easiest for users to understand and, as a bonus, permits the most flexibility and performance. But it sounds like that is not on the table right now.
A second-best solution could be to make it possible to ban or lint-away any usage of the language that incurs ordering dependencies, so that projects could opt-into the subset of the language where ordering doesn't matter.
Fallback Solution
Today, we embed the TypeScript checker in a custom toolchain that is used locally and during a remote project publishing step. But we don't have a custom LSP - we reuse the default VS Code LSP and configure it via a generated
tsconfigwritten to the source directory. So for true consistency, it appears that we need to update the toolchain to ensure that we are matching the canonical TypeScript file load order.Is this canonical load order specified anywhere? Is there a way to reuse TypeScript's existing logic here? It would be great to reuse that code so that if TypeScript ever changes the order, our toolchain continues to match.
RyanCavanaugh commentedon Jan 13, 2023
I'll give a rough sketch. The order is:
filesarray, in its original orderincludearray, the constituents of which I believe are alphabetically sorted (not sure) on a per-pattern basisThis order is not final; it's then stably sorted by the dependency graph implied by
referencedirectives andimportdirectives.dragomirtitian commentedon Feb 23, 2023
Ryan Cavanaugh (@RyanCavanaugh) This issue now appears to not happen anymore, and inference has stabilized on
Promise<any>. This happened between5.0.0-dev.20230210and5.0.0-dev.20230216(can't pin point more accurately as playground has a gap of version between those dates)Was this intentional? Is this going to remain so going forward?
RyanCavanaugh commentedon Feb 23, 2023
AFAIK, we haven't done anything which we believed to be a fix.