Infer AssertsIdentifier type predicates
This extends the type predicate inference from #57465 to cover "asserts identifier" predicates as well. For example:
// function isNumber(x: unknown): asserts x is number
function isNumber(x: unknown) {
if (typeof x !== 'number') {
throw new Error(`expected a number, got ${x}`);
}
}
or:
// function assertNonNullish<T>(x: T): asserts x is NonNullable<T>
function assertNonNullish<T>(x: T) {
if (x != null) {
return;
}
throw new Error();
}
The constraints for inference are:
- We're working with a function statement. Not a constructor, getter, setter, method, arrow function, or function expression. (This is significantly more restrictive than for "identifier" predicates, see https://github.com/microsoft/TypeScript/pull/33622 for why.)
- The function does not have an explicit return type annotation, but is inferred to return
voidorundefined. - The function takes at least one parameter that it does not mutate.
The criterion winds up being a bit simpler than it was in #57465:
- Check the type of the parameter at each
returnsite (including an implicit return at the end of the function). - Union these types.
- If this is different than the initial type of the parameter, then we've got an assertion function.
I wound up implementing "different than" with an assignability check since branching constructs can sometimes change the representation of a parameter's type in superficial ways, e.g. unknown can become {} | null | undefined.
There's no equivalent of the "false check" that we needed to infer identifier type predicates. Assertion predicates are inherently one-sided. If they fail, your code will throw. This means that we can infer assertions even when the negative type can't be represented. For example:
// function assertIsShortString(x: unknown): asserts x is string
function assertIsShortString(x: unknown) {
if (typeof x !== 'string') {
throw new Error('Expected string');
} else if (x.length > 10) {
throw new Error('Expected short string');
}
}
This wouldn't work as a type predicate (x is string) because you can't represent "all types except short strings." But it's fine as an imprecise assertion, since there's no way to observe the negative case.
A few other things to note:
- This allows assertions to flow (#51326). In particular, this lets CFA "see through" a function that calls a type predicate and throws if it fails (e.g.
assertFoocallsisFoo). - This only infers assertions with a type:
asserts x is T, notasserts x. The latter would also be interesting, but that feels like a different problem. - This only infers a non-returning code path via its effect on types. This feels a little strange/risky to me since it means this code runs on all sorts of functions that don't throw. But it does work, and this is a natural way to handle all the different patterns (early throw, early return).
- One of the fourslash tests found a bug with unused parameters getting marked as used. This turns out to be an issue with inferred type predicates as well, see #58493.
It's possible that the "asserted type" really is the same as the parameter's declared type, but TS isn't able to figure that out. This happened for one of the baselines. In this case we'll infer a useless type predicate (function f(x: T): asserts x is T). This is noisy but won't produce spurious errors. There's one example of this in the baselines.
I didn't observe any slowdowns from this change locally and there's some reason to hope that's the case. For inferred type predicates, the expensive part was the "false" checks (see https://github.com/microsoft/TypeScript/pull/57465#issuecomment-1976704315). There's no need to do that for assertion functions, though, so we won't pay that price. On the other hand, there might be more implicitly void-returning functions than implicitly boolean-returning functions, so we'll see!
If this is different than the initial type of the parameter, then we've got an assertion function.
This feels like it’s going to turn a lot of functions into assertions that were never intended to be, just because a parameter was narrowed somewhere in the function.
If this is different than the initial type of the parameter, then we've got an assertion function.
This feels like it’s going to turn a lot of functions into assertions that were never intended to be, just because a parameter was narrowed somewhere in the function.
It's not enough for the parameter to be narrowed somewhere in the function. The function has to throw in a way that's tied to that narrowing.
We could do an experiment similar to #58173 to see how often this triggers.
Ah, okay - you didn’t mention that in the description in the OP, the algorithm you laid out was just that you check all the return points, not also the throwing points.
Ah, okay - you didn’t mention that in the description in the OP, the algorithm you laid out was just that you check all the return points, not also the throwing points.
The algorithm only looks at parameter types when you return, or (important!) at the implicit return at the end of a function. When you union those types, the only way I can think of that you'd get something distinct from the initial parameter type is by having a code path that throws or does the equivalent (calls another assertion function or never-returning function, or goes into an infinite loop).
Maybe an example would make it clearer how this works:
function assertABC(x: 'A' | 'B' | 'C' | 'D' | 'E') {
if (x === 'A') {
return; // type of x here is 'A'
} else if (x === 'B' || x === 'C') {
throw new Error();
}
// implicit return; type of x here is 'D' | E'
}
Unioning the types of x gives 'A' | 'D' | 'E'. Since 'A' | D' | 'E' is distinct from 'A' | 'B' | 'C' | 'D' | 'E', we have a type assertion function.
If you take a look at the code for the algorithm, it's all about return. The association with throw is implied by the check on the types.
Ah, so it’s based on how TS re-merges control-flow branches by unioning the narrowed types back together, that’s clever. However do note - that can sometimes create an observably different type on the other side (see: subtype reduction, introducing intersections, etc.)
Forgive me if you’ve accounted for all this already - I’m just spouting the caveats that come to mind when I think about this.
Ah, so it’s based on how TS re-merges control-flow branches by unioning the narrowed types back together, that’s clever. However do note - that can sometimes create an observably different type on the other side (see: subtype reduction, introducing intersections, etc.)
I won't infer an assertion predicate so long as the initial parameter type is assignable to the asserted type, so superficial differences shouldn't matter. But there are some cases where TS can't figure out the relationship. There's one example of this in the baselines (see my comments on the code). There will probably be others in the wild.
This change would feel less aggressive if I could detect whether there was a code path that throws in the function, but I couldn't find anything that quite did what I wanted.
@typescript-bot test it @typescript-bot pack this
for fun
Starting jobs; this comment will be updated as builds start and complete.
| Command | Status | Results |
|---|---|---|
test top400 |
✅ Started | 👀 Results |
user test this |
✅ Started | ✅ Results |
run dt |
✅ Started | ✅ Results |
perf test this faster |
✅ Started | 👀 Results |
pack this |
✅ Started | ✅ Results |
Hey @jakebailey, I've packed this into an installable tgz. You can install it for testing by referencing it in your package.json like so:
{
"devDependencies": {
"typescript": "https://typescript.visualstudio.com/cf7ac146-d525-443c-b23c-0d58337efebc/_apis/build/builds/161690/artifacts?artifactName=tgz&fileId=0BFA3D3A0A0BB0B903EE356283DCF9D638B724930087ECCE5D71B4C18A4DA8BB02&fileName=/typescript-5.5.0-insiders.20240510.tgz"
}
}
and then running npm install.
There is also a playground for this build and an npm module you can use via "typescript": "npm:@typescript-deploys/[email protected]".;
Hey @jakebailey, the results of running the DT tests are ready.
Everything looks the same!
@jakebailey Here are the results of running the user tests comparing main and refs/pull/58495/merge:
Everything looks good!
@jakebailey The results of the perf run you requested are in!
Here they are:
tsc
Comparison Report - baseline..pr| Metric | baseline | pr | Delta | Best | Worst | p-value |
|---|---|---|---|---|---|---|
| Compiler-Unions - node (v18.15.0, x64) | ||||||
| Errors | 30 | 30 | ~ | ~ | ~ | p=1.000 n=6 |
| Symbols | 62,154 | 62,154 | ~ | ~ | ~ | p=1.000 n=6 |
| Types | 50,248 | 50,255 | +7 (+ 0.01%) | ~ | ~ | p=0.001 n=6 |
| Memory used | 192,824k (± 0.77%) | 193,524k (± 0.95%) | +700k (+ 0.36%) | 192,296k | 195,932k | p=0.031 n=6 |
| Parse Time | 1.55s (± 1.08%) | 1.54s (± 1.95%) | ~ | 1.51s | 1.58s | p=0.681 n=6 |
| Bind Time | 0.86s (± 1.40%) | 0.86s (± 0.47%) | ~ | 0.86s | 0.87s | p=0.863 n=6 |
| Check Time | 11.29s (± 0.59%) | 11.32s (± 0.63%) | ~ | 11.23s | 11.40s | p=0.748 n=6 |
| Emit Time | 3.15s (± 0.33%) | 3.14s (± 0.82%) | ~ | 3.11s | 3.19s | p=0.112 n=6 |
| Total Time | 16.86s (± 0.49%) | 16.86s (± 0.43%) | ~ | 16.74s | 16.93s | p=0.872 n=6 |
| angular-1 - node (v18.15.0, x64) | ||||||
| Errors | 5 | 5 | ~ | ~ | ~ | p=1.000 n=6 |
| Symbols | 944,110 | 944,107 | -3 (- 0.00%) | ~ | ~ | p=0.001 n=6 |
| Types | 407,140 | 407,147 | +7 (+ 0.00%) | ~ | ~ | p=0.001 n=6 |
| Memory used | 1,222,027k (± 0.00%) | 1,222,174k (± 0.00%) | +147k (+ 0.01%) | 1,222,093k | 1,222,232k | p=0.008 n=6 |
| Parse Time | 8.07s (± 0.31%) | 8.12s (± 0.64%) | +0.05s (+ 0.66%) | 8.05s | 8.20s | p=0.043 n=6 |
| Bind Time | 2.25s (± 0.67%) | 2.25s (± 0.73%) | ~ | 2.22s | 2.26s | p=1.000 n=6 |
| Check Time | 36.49s (± 0.33%) | 36.59s (± 0.44%) | ~ | 36.34s | 36.81s | p=0.229 n=6 |
| Emit Time | 17.53s (± 0.66%) | 17.57s (± 0.40%) | ~ | 17.49s | 17.69s | p=0.423 n=6 |
| Total Time | 64.33s (± 0.30%) | 64.53s (± 0.24%) | ~ | 64.28s | 64.70s | p=0.109 n=6 |
| mui-docs - node (v18.15.0, x64) | ||||||
| Errors | 5 | 5 | ~ | ~ | ~ | p=1.000 n=6 |
| Symbols | 1,961,283 | 1,961,283 | ~ | ~ | ~ | p=1.000 n=6 |
| Types | 696,900 | 696,939 | +39 (+ 0.01%) | ~ | ~ | p=0.001 n=6 |
| Memory used | 1,777,974k (± 0.00%) | 1,778,082k (± 0.00%) | +108k (+ 0.01%) | 1,778,048k | 1,778,110k | p=0.005 n=6 |
| Parse Time | 9.86s (± 0.38%) | 9.86s (± 0.31%) | ~ | 9.81s | 9.90s | p=0.686 n=6 |
| Bind Time | 3.36s (± 0.71%) | 3.37s (± 0.82%) | ~ | 3.32s | 3.40s | p=0.370 n=6 |
| Check Time | 82.68s (± 0.18%) | 82.72s (± 0.23%) | ~ | 82.45s | 83.02s | p=1.000 n=6 |
| Emit Time | 0.21s (± 3.95%) | 0.20s (± 2.54%) | ~ | 0.20s | 0.21s | p=0.523 n=6 |
| Total Time | 96.12s (± 0.12%) | 96.15s (± 0.22%) | ~ | 95.89s | 96.49s | p=1.000 n=6 |
| self-build-src - node (v18.15.0, x64) | ||||||
| Errors | 0 | 0 | ~ | ~ | ~ | p=1.000 n=6 |
| Symbols | 1,220,400 | 1,220,443 | +43 (+ 0.00%) | ~ | ~ | p=0.001 n=6 |
| Types | 258,967 | 258,989 | +22 (+ 0.01%) | ~ | ~ | p=0.001 n=6 |
| Memory used | 2,335,959k (± 0.03%) | 2,336,372k (± 0.04%) | ~ | 2,335,223k | 2,337,305k | p=0.471 n=6 |
| Parse Time | 4.97s (± 1.31%) | 4.95s (± 0.83%) | ~ | 4.91s | 5.00s | p=0.378 n=6 |
| Bind Time | 1.88s (± 0.73%) | 1.88s (± 0.93%) | ~ | 1.85s | 1.90s | p=1.000 n=6 |
| Check Time | 33.77s (± 0.36%) | 33.79s (± 0.32%) | ~ | 33.62s | 33.91s | p=0.936 n=6 |
| Emit Time | 2.65s (± 2.29%) | 2.63s (± 2.95%) | ~ | 2.51s | 2.74s | p=0.521 n=6 |
| Total Time | 43.30s (± 0.24%) | 43.25s (± 0.29%) | ~ | 43.02s | 43.37s | p=0.575 n=6 |
| self-build-src-public-api - node (v18.15.0, x64) | ||||||
| Errors | 0 | 0 | ~ | ~ | ~ | p=1.000 n=6 |
| Symbols | 1,220,400 | 1,220,443 | +43 (+ 0.00%) | ~ | ~ | p=0.001 n=6 |
| Types | 258,967 | 258,989 | +22 (+ 0.01%) | ~ | ~ | p=0.001 n=6 |
| Memory used | 2,411,497k (± 0.01%) | 2,411,343k (± 0.02%) | ~ | 2,410,547k | 2,412,209k | p=0.575 n=6 |
| Parse Time | 6.31s (± 0.60%) | 6.30s (± 0.90%) | ~ | 6.22s | 6.38s | p=0.810 n=6 |
| Bind Time | 2.05s (± 0.95%) | 2.04s (± 1.13%) | ~ | 2.02s | 2.07s | p=0.808 n=6 |
| Check Time | 40.18s (± 0.36%) | 40.26s (± 0.30%) | ~ | 40.09s | 40.45s | p=0.298 n=6 |
| Emit Time | 3.20s (± 2.60%) | 3.19s (± 1.84%) | ~ | 3.08s | 3.25s | p=0.470 n=6 |
| Total Time | 51.75s (± 0.42%) | 51.79s (± 0.29%) | ~ | 51.61s | 52.01s | p=0.689 n=6 |
| self-compiler - node (v18.15.0, x64) | ||||||
| Errors | 0 | 0 | ~ | ~ | ~ | p=1.000 n=6 |
| Symbols | 256,559 | 256,601 | +42 (+ 0.02%) | ~ | ~ | p=0.001 n=6 |
| Types | 104,270 | 104,285 | +15 (+ 0.01%) | ~ | ~ | p=0.001 n=6 |
| Memory used | 425,708k (± 0.03%) | 425,822k (± 0.01%) | ~ | 425,752k | 425,882k | p=0.066 n=6 |
| Parse Time | 3.38s (± 0.63%) | 3.37s (± 0.49%) | ~ | 3.34s | 3.38s | p=0.331 n=6 |
| Bind Time | 1.31s (± 0.89%) | 1.31s (± 0.57%) | ~ | 1.30s | 1.32s | p=0.796 n=6 |
| Check Time | 17.93s (± 0.34%) | 17.97s (± 0.38%) | ~ | 17.87s | 18.03s | p=0.335 n=6 |
| Emit Time | 1.37s (± 2.14%) | 1.37s | ~ | ~ | ~ | p=0.655 n=6 |
| Total Time | 23.99s (± 0.22%) | 24.02s (± 0.29%) | ~ | 23.92s | 24.08s | p=0.688 n=6 |
| ts-pre-modules - node (v18.15.0, x64) | ||||||
| Errors | 35 | 35 | ~ | ~ | ~ | p=1.000 n=6 |
| Symbols | 224,575 | 224,583 | +8 (+ 0.00%) | ~ | ~ | p=0.001 n=6 |
| Types | 93,785 | 93,792 | +7 (+ 0.01%) | ~ | ~ | p=0.001 n=6 |
| Memory used | 369,898k (± 0.03%) | 369,935k (± 0.03%) | ~ | 369,870k | 370,123k | p=0.688 n=6 |
| Parse Time | 3.48s (± 0.47%) | 3.51s (± 0.67%) | ~ | 3.48s | 3.53s | p=0.122 n=6 |
| Bind Time | 1.93s (± 0.53%) | 1.93s (± 0.76%) | ~ | 1.92s | 1.96s | p=0.605 n=6 |
| Check Time | 19.36s (± 0.40%) | 19.36s (± 0.42%) | ~ | 19.26s | 19.49s | p=0.872 n=6 |
| Emit Time | 0.00s | 0.00s | ~ | ~ | ~ | p=1.000 n=6 |
| Total Time | 24.77s (± 0.35%) | 24.80s (± 0.34%) | ~ | 24.69s | 24.94s | p=0.748 n=6 |
| vscode - node (v18.15.0, x64) | ||||||
| Errors | 0 | 2 | 🔻+2 (+ ∞%) | ~ | ~ | p=0.001 n=6 |
| Symbols | 2,820,491 | 2,820,496 | +5 (+ 0.00%) | ~ | ~ | p=0.001 n=6 |
| Types | 956,787 | 956,831 | +44 (+ 0.00%) | ~ | ~ | p=0.001 n=6 |
| Memory used | 2,992,366k (± 0.00%) | 2,992,554k (± 0.00%) | +188k (+ 0.01%) | 2,992,461k | 2,992,599k | p=0.005 n=6 |
| Parse Time | 13.84s (± 0.33%) | 13.83s (± 0.36%) | ~ | 13.75s | 13.88s | p=0.936 n=6 |
| Bind Time | 4.16s (± 2.07%) | 4.30s (± 2.20%) | ~ | 4.11s | 4.37s | p=0.063 n=6 |
| Check Time | 73.32s (± 0.29%) | 73.45s (± 0.63%) | ~ | 72.95s | 74.28s | p=0.689 n=6 |
| Emit Time | 23.64s (± 0.62%) | 23.40s (± 0.60%) | -0.24s (- 1.00%) | 23.25s | 23.66s | p=0.020 n=6 |
| Total Time | 114.95s (± 0.22%) | 114.98s (± 0.52%) | ~ | 114.36s | 116.12s | p=0.689 n=6 |
| webpack - node (v18.15.0, x64) | ||||||
| Errors | 0 | 0 | ~ | ~ | ~ | p=1.000 n=6 |
| Symbols | 265,866 | 265,866 | ~ | ~ | ~ | p=1.000 n=6 |
| Types | 108,401 | 108,402 | +1 (+ 0.00%) | ~ | ~ | p=0.001 n=6 |
| Memory used | 410,604k (± 0.01%) | 410,596k (± 0.01%) | ~ | 410,547k | 410,639k | p=1.000 n=6 |
| Parse Time | 4.77s (± 1.10%) | 4.75s (± 0.54%) | ~ | 4.71s | 4.79s | p=0.169 n=6 |
| Bind Time | 2.08s (± 0.88%) | 2.07s (± 1.22%) | ~ | 2.03s | 2.10s | p=0.622 n=6 |
| Check Time | 21.00s (± 0.26%) | 21.07s (± 0.28%) | ~ | 20.99s | 21.16s | p=0.093 n=6 |
| Emit Time | 0.00s | 0.00s | ~ | ~ | ~ | p=1.000 n=6 |
| Total Time | 27.85s (± 0.30%) | 27.88s (± 0.31%) | ~ | 27.79s | 28.03s | p=0.689 n=6 |
| xstate-main - node (v18.15.0, x64) | ||||||
| Errors | 0 | 0 | ~ | ~ | ~ | p=1.000 n=6 |
| Symbols | 524,576 | 524,576 | ~ | ~ | ~ | p=1.000 n=6 |
| Types | 178,847 | 178,851 | +4 (+ 0.00%) | ~ | ~ | p=0.001 n=6 |
| Memory used | 462,623k (± 0.03%) | 462,577k (± 0.00%) | ~ | 462,533k | 462,600k | p=1.000 n=6 |
| Parse Time | 3.12s (± 1.24%) | 3.11s (± 0.86%) | ~ | 3.08s | 3.16s | p=0.570 n=6 |
| Bind Time | 1.17s (± 0.76%) | 1.17s (± 0.76%) | ~ | 1.16s | 1.18s | p=1.000 n=6 |
| Check Time | 18.21s (± 0.64%) | 18.21s (± 0.57%) | ~ | 18.08s | 18.33s | p=0.936 n=6 |
| Emit Time | 0.00s | 0.00s | ~ | ~ | ~ | p=1.000 n=6 |
| Total Time | 22.49s (± 0.49%) | 22.50s (± 0.42%) | ~ | 22.37s | 22.62s | p=0.873 n=6 |
- node (v18.15.0, x64)
- Compiler-Unions - node (v18.15.0, x64)
- angular-1 - node (v18.15.0, x64)
- mui-docs - node (v18.15.0, x64)
- self-build-src - node (v18.15.0, x64)
- self-build-src-public-api - node (v18.15.0, x64)
- self-compiler - node (v18.15.0, x64)
- ts-pre-modules - node (v18.15.0, x64)
- vscode - node (v18.15.0, x64)
- webpack - node (v18.15.0, x64)
- xstate-main - node (v18.15.0, x64)
| Benchmark | Name | Iterations |
|---|---|---|
| Current | pr | 6 |
| Baseline | baseline | 6 |
Developer Information:
Perf impact looks pretty minimal… but what are those two new errors in VS Code?
@jakebailey Here are the results of running the top 400 repos comparing main and refs/pull/58495/merge:
Something interesting changed - please have a look.
Details
darkreader/darkreader
1 of 5 projects failed to build with the old tsc and were ignored
tests/inject/tsconfig.json
error TS2775: Assertions require every name in the call target to be declared with an explicit type annotation.
src/tsconfig.json
error TS2775: Assertions require every name in the call target to be declared with an explicit type annotation.
src/api/tsconfig.json
error TS2775: Assertions require every name in the call target to be declared with an explicit type annotation.
invoke-ai/InvokeAI
invokeai/frontend/web/tsconfig.json
error TS2775: Assertions require every name in the call target to be declared with an explicit type annotation.- invokeai/frontend/web/src/features/metadata/util/validators.ts#L32
- invokeai/frontend/web/src/features/metadata/util/validators.ts#L37
- invokeai/frontend/web/src/features/metadata/util/validators.ts#L42
- invokeai/frontend/web/src/features/metadata/util/validators.ts#L50
- invokeai/frontend/web/src/features/metadata/util/validators.ts#L60
- invokeai/frontend/web/src/features/metadata/util/validators.ts#L68
- invokeai/frontend/web/src/features/metadata/util/validators.ts#L78
- invokeai/frontend/web/src/features/metadata/util/validators.ts#L86
- invokeai/frontend/web/src/features/metadata/util/validators.ts#L96
- invokeai/frontend/web/src/features/metadata/util/validators.ts#L104
- invokeai/frontend/web/src/features/metadata/util/validators.ts#L117
- invokeai/frontend/web/src/features/metadata/util/validators.ts#L122
- invokeai/frontend/web/src/features/metadata/util/validators.ts#L128
microsoft/vscode
4 of 54 projects failed to build with the old tsc and were ignored
src/tsconfig.tsec.json
error TS2339: Property 'description' does not exist on type 'TreeItem'.error TS2339: Property 'accessibilityInformation' does not exist on type 'TreeItem'.
src/tsconfig.json
error TS2339: Property 'description' does not exist on type 'TreeItem'.error TS2339: Property 'accessibilityInformation' does not exist on type 'TreeItem'.
Assertions require every name in the call target to be declared with an explicit type annotation.
Ouch. I forgot that was something the compiler checked for. The existence of that error means you have to be very careful about exactly what you infer as an assertion…
Summary of breaks (https://github.com/microsoft/TypeScript/pull/58495#issuecomment-2105358748):
- darkreader: we inferred that an arrow function was a type assertion predicate, which doesn't generally work.
- InvokeAI: same;
validateBaseCompatibilityis an arrow function. This PR correctly infers that it returns a type assertion predicate, but this results in TS2775. If it were a function statement, the inferred type assertion predicate works fine. - vscode: In this case, we infer a type assertion predicate for a method. Again, this doesn't always work and can produce TS2776. But that's not what happens here. The
ExtHostTreeView.validateTreeItemmethod becomes a type assertion predicate. This, in turn, exposes what I believe had been a latent TS bug: #58518
The fix for all of these is to not infer type assertion predicates for methods or arrow functions because this can produce a confusing error at the call site. See #33622 for why. This definitely limits the scope of this PR: the latest version only runs on plain old function statements.
I think the nicest win from this PR is that it lets type predicates naturally flow through assertion wrappers:
declare function isFoo(x: any): x is Foo;
// function inferFromType(x: unknown): asserts x is Foo
function inferFromType(x: unknown) {
if (!isFoo(x)) {
throw new Error();
}
}
I think the nicest win from this PR is that it lets type predicates naturally flow through assertion wrappers:
This is dope 🚀
@typescript-bot test it @typescript-bot pack this
Starting jobs; this comment will be updated as builds start and complete.
| Command | Status | Results |
|---|---|---|
test top400 |
✅ Started | ✅ Results |
user test this |
✅ Started | 👀 Results |
run dt |
✅ Started | ✅ Results |
perf test this faster |
✅ Started | 👀 Results |
pack this |
✅ Started | ✅ Results |
Hey @jakebailey, I've packed this into an installable tgz. You can install it for testing by referencing it in your package.json like so:
{
"devDependencies": {
"typescript": "https://typescript.visualstudio.com/cf7ac146-d525-443c-b23c-0d58337efebc/_apis/build/builds/161715/artifacts?artifactName=tgz&fileId=33CA50AFB7B259ACD3FE936AA8261E8754CA2DEC5411359B7E3C7C6088AA876F02&fileName=/typescript-5.5.0-insiders.20240513.tgz"
}
}
and then running npm install.
There is also a playground for this build and an npm module you can use via "typescript": "npm:@typescript-deploys/[email protected]".;
Hey @jakebailey, the results of running the DT tests are ready.
Everything looks the same!
@jakebailey Here are the results of running the user tests comparing main and refs/pull/58495/merge:
Something interesting changed - please have a look.
Details
minimatch
/mnt/ts_downloads/_/m/minimatch/tsconfig.json
- [NEW]
error TS2775: Assertions require every name in the call target to be declared with an explicit type annotation.- /mnt/ts_downloads/_/m/minimatch/node_modules/minimatch/minimatch.js(116,3)
- /mnt/ts_downloads/_/m/minimatch/node_modules/minimatch/minimatch.js(133,3)
- /mnt/ts_downloads/_/m/minimatch/node_modules/minimatch/minimatch.js(260,3)
- /mnt/ts_downloads/_/m/minimatch/node_modules/minimatch/minimatch.js(297,3)
@jakebailey The results of the perf run you requested are in!
Here they are:
tsc
Comparison Report - baseline..pr| Metric | baseline | pr | Delta | Best | Worst | p-value |
|---|---|---|---|---|---|---|
| Compiler-Unions - node (v18.15.0, x64) | ||||||
| Errors | 30 | 30 | ~ | ~ | ~ | p=1.000 n=6 |
| Symbols | 62,154 | 62,154 | ~ | ~ | ~ | p=1.000 n=6 |
| Types | 50,248 | 50,252 | +4 (+ 0.01%) | ~ | ~ | p=0.001 n=6 |
| Memory used | 193,496k (± 0.95%) | 195,371k (± 0.77%) | +1,874k (+ 0.97%) | 192,313k | 196,084k | p=0.020 n=6 |
| Parse Time | 1.55s (± 1.95%) | 1.55s (± 1.49%) | ~ | 1.51s | 1.58s | p=1.000 n=6 |
| Bind Time | 0.86s (± 0.94%) | 0.86s (± 0.47%) | ~ | 0.86s | 0.87s | p=0.584 n=6 |
| Check Time | 11.28s (± 0.34%) | 11.32s (± 0.32%) | ~ | 11.30s | 11.39s | p=0.081 n=6 |
| Emit Time | 3.14s (± 0.55%) | 3.13s (± 0.87%) | ~ | 3.09s | 3.16s | p=1.000 n=6 |
| Total Time | 16.83s (± 0.36%) | 16.86s (± 0.26%) | ~ | 16.82s | 16.94s | p=0.295 n=6 |
| angular-1 - node (v18.15.0, x64) | ||||||
| Errors | 5 | 5 | ~ | ~ | ~ | p=1.000 n=6 |
| Symbols | 944,110 | 944,111 | +1 (+ 0.00%) | ~ | ~ | p=0.001 n=6 |
| Types | 407,140 | 407,144 | +4 (+ 0.00%) | ~ | ~ | p=0.001 n=6 |
| Memory used | 1,222,086k (± 0.00%) | 1,222,194k (± 0.00%) | +108k (+ 0.01%) | 1,222,138k | 1,222,260k | p=0.020 n=6 |
| Parse Time | 6.78s (± 0.63%) | 6.77s (± 0.28%) | ~ | 6.75s | 6.80s | p=0.810 n=6 |
| Bind Time | 1.88s (± 0.64%) | 1.89s (± 0.40%) | ~ | 1.88s | 1.90s | p=0.111 n=6 |
| Check Time | 31.25s (± 0.53%) | 31.34s (± 0.43%) | ~ | 31.13s | 31.53s | p=0.298 n=6 |
| Emit Time | 14.72s (± 0.54%) | 14.77s (± 0.77%) | ~ | 14.64s | 14.93s | p=0.574 n=6 |
| Total Time | 54.62s (± 0.26%) | 54.77s (± 0.39%) | ~ | 54.55s | 55.03s | p=0.128 n=6 |
| mui-docs - node (v18.15.0, x64) | ||||||
| Errors | 5 | 5 | ~ | ~ | ~ | p=1.000 n=6 |
| Symbols | 1,961,349 | 1,961,349 | ~ | ~ | ~ | p=1.000 n=6 |
| Types | 696,910 | 696,910 | ~ | ~ | ~ | p=1.000 n=6 |
| Memory used | 1,778,101k (± 0.00%) | 1,778,109k (± 0.00%) | ~ | 1,778,068k | 1,778,142k | p=0.521 n=6 |
| Parse Time | 6.78s (± 0.31%) | 6.79s (± 0.59%) | ~ | 6.77s | 6.87s | p=0.655 n=6 |
| Bind Time | 2.31s (± 0.33%) | 2.31s (± 0.60%) | ~ | 2.29s | 2.32s | p=0.453 n=6 |
| Check Time | 57.05s (± 0.49%) | 56.97s (± 0.64%) | ~ | 56.51s | 57.51s | p=0.689 n=6 |
| Emit Time | 0.14s | 0.14s | ~ | ~ | ~ | p=1.000 n=6 |
| Total Time | 66.29s (± 0.43%) | 66.20s (± 0.52%) | ~ | 65.73s | 66.73s | p=0.575 n=6 |
| self-build-src - node (v18.15.0, x64) | ||||||
| Errors | 0 | 0 | ~ | ~ | ~ | p=1.000 n=6 |
| Symbols | 1,221,120 | 1,221,163 | +43 (+ 0.00%) | ~ | ~ | p=0.001 n=6 |
| Types | 259,211 | 259,228 | +17 (+ 0.01%) | ~ | ~ | p=0.001 n=6 |
| Memory used | 2,337,130k (± 0.02%) | 2,337,212k (± 0.03%) | ~ | 2,336,192k | 2,338,326k | p=1.000 n=6 |
| Parse Time | 4.98s (± 1.51%) | 4.99s (± 0.83%) | ~ | 4.93s | 5.03s | p=1.000 n=6 |
| Bind Time | 1.87s (± 0.76%) | 1.88s (± 0.78%) | ~ | 1.86s | 1.90s | p=0.222 n=6 |
| Check Time | 33.72s (± 0.33%) | 33.81s (± 0.39%) | ~ | 33.64s | 33.96s | p=0.378 n=6 |
| Emit Time | 2.67s (± 1.96%) | 2.62s (± 2.44%) | ~ | 2.55s | 2.71s | p=0.172 n=6 |
| Total Time | 43.26s (± 0.29%) | 43.33s (± 0.23%) | ~ | 43.23s | 43.48s | p=0.378 n=6 |
| self-build-src-public-api - node (v18.15.0, x64) | ||||||
| Errors | 0 | 0 | ~ | ~ | ~ | p=1.000 n=6 |
| Symbols | 1,221,120 | 1,221,163 | +43 (+ 0.00%) | ~ | ~ | p=0.001 n=6 |
| Types | 259,211 | 259,228 | +17 (+ 0.01%) | ~ | ~ | p=0.001 n=6 |
| Memory used | 2,411,894k (± 0.02%) | 2,412,608k (± 0.04%) | ~ | 2,411,592k | 2,413,650k | p=0.173 n=6 |
| Parse Time | 5.22s (± 0.95%) | 5.23s (± 1.18%) | ~ | 5.16s | 5.34s | p=0.873 n=6 |
| Bind Time | 1.69s (± 0.24%) | 1.69s (± 0.30%) | ~ | 1.69s | 1.70s | p=0.114 n=6 |
| Check Time | 34.31s (± 0.32%) | 34.26s (± 0.38%) | ~ | 34.08s | 34.45s | p=0.378 n=6 |
| Emit Time | 2.69s (± 0.47%) | 2.64s (± 3.18%) | ~ | 2.55s | 2.75s | p=0.378 n=6 |
| Total Time | 43.93s (± 0.30%) | 43.84s (± 0.45%) | ~ | 43.53s | 44.02s | p=0.521 n=6 |
| self-compiler - node (v18.15.0, x64) | ||||||
| Errors | 0 | 0 | ~ | ~ | ~ | p=1.000 n=6 |
| Symbols | 256,716 | 256,758 | +42 (+ 0.02%) | ~ | ~ | p=0.001 n=6 |
| Types | 104,288 | 104,302 | +14 (+ 0.01%) | ~ | ~ | p=0.001 n=6 |
| Memory used | 425,755k (± 0.02%) | 425,930k (± 0.01%) | +175k (+ 0.04%) | 425,883k | 425,967k | p=0.005 n=6 |
| Parse Time | 3.37s (± 0.41%) | 3.38s (± 0.64%) | ~ | 3.35s | 3.41s | p=0.462 n=6 |
| Bind Time | 1.32s (± 0.68%) | 1.32s (± 0.89%) | ~ | 1.31s | 1.34s | p=0.672 n=6 |
| Check Time | 17.89s (± 0.42%) | 17.93s (± 0.29%) | ~ | 17.86s | 17.99s | p=0.297 n=6 |
| Emit Time | 1.35s (± 0.94%) | 1.37s (± 1.07%) | +0.02s (+ 1.60%) | 1.36s | 1.40s | p=0.032 n=6 |
| Total Time | 23.93s (± 0.29%) | 24.00s (± 0.21%) | +0.07s (+ 0.31%) | 23.94s | 24.07s | p=0.044 n=6 |
| ts-pre-modules - node (v18.15.0, x64) | ||||||
| Errors | 35 | 35 | ~ | ~ | ~ | p=1.000 n=6 |
| Symbols | 224,575 | 224,583 | +8 (+ 0.00%) | ~ | ~ | p=0.001 n=6 |
| Types | 93,785 | 93,791 | +6 (+ 0.01%) | ~ | ~ | p=0.001 n=6 |
| Memory used | 369,965k (± 0.04%) | 369,917k (± 0.02%) | ~ | 369,837k | 370,027k | p=1.000 n=6 |
| Parse Time | 2.82s (± 0.92%) | 2.83s (± 0.73%) | ~ | 2.81s | 2.86s | p=0.685 n=6 |
| Bind Time | 1.58s (± 0.84%) | 1.59s (± 1.04%) | ~ | 1.57s | 1.61s | p=0.738 n=6 |
| Check Time | 15.68s (± 0.48%) | 15.69s (± 0.22%) | ~ | 15.63s | 15.72s | p=0.809 n=6 |
| Emit Time | 0.00s | 0.00s | ~ | ~ | ~ | p=1.000 n=6 |
| Total Time | 20.09s (± 0.42%) | 20.11s (± 0.28%) | ~ | 20.03s | 20.19s | p=0.574 n=6 |
| vscode - node (v18.15.0, x64) | ||||||
| Errors | 0 | 0 | ~ | ~ | ~ | p=1.000 n=6 |
| Symbols | 2,821,517 | 2,821,518 | +1 (+ 0.00%) | ~ | ~ | p=0.001 n=6 |
| Types | 957,198 | 957,198 | ~ | ~ | ~ | p=1.000 n=6 |
| Memory used | 2,993,753k (± 0.00%) | 2,993,703k (± 0.00%) | ~ | 2,993,596k | 2,993,776k | p=0.230 n=6 |
| Parse Time | 13.80s (± 0.26%) | 13.82s (± 0.11%) | ~ | 13.80s | 13.84s | p=0.167 n=6 |
| Bind Time | 4.14s (± 0.52%) | 4.14s (± 0.36%) | ~ | 4.13s | 4.17s | p=0.742 n=6 |
| Check Time | 73.44s (± 0.34%) | 73.18s (± 0.19%) | ~ | 73.02s | 73.37s | p=0.066 n=6 |
| Emit Time | 23.48s (± 0.35%) | 23.51s (± 0.67%) | ~ | 23.32s | 23.73s | p=0.873 n=6 |
| Total Time | 114.86s (± 0.23%) | 114.65s (± 0.15%) | ~ | 114.44s | 114.94s | p=0.199 n=6 |
| webpack - node (v18.15.0, x64) | ||||||
| Errors | 0 | 0 | ~ | ~ | ~ | p=1.000 n=6 |
| Symbols | 265,866 | 265,866 | ~ | ~ | ~ | p=1.000 n=6 |
| Types | 108,401 | 108,401 | ~ | ~ | ~ | p=1.000 n=6 |
| Memory used | 410,651k (± 0.03%) | 410,560k (± 0.02%) | ~ | 410,508k | 410,651k | p=0.128 n=6 |
| Parse Time | 4.76s (± 0.84%) | 4.77s (± 1.23%) | ~ | 4.68s | 4.85s | p=0.936 n=6 |
| Bind Time | 2.07s (± 0.66%) | 2.05s (± 0.95%) | -0.02s (- 1.21%) | 2.02s | 2.07s | p=0.033 n=6 |
| Check Time | 20.98s (± 0.36%) | 20.96s (± 0.27%) | ~ | 20.89s | 21.04s | p=0.378 n=6 |
| Emit Time | 0.00s | 0.00s | ~ | ~ | ~ | p=1.000 n=6 |
| Total Time | 27.82s (± 0.38%) | 27.77s (± 0.30%) | ~ | 27.68s | 27.87s | p=0.295 n=6 |
| xstate-main - node (v18.15.0, x64) | ||||||
| Errors | 0 | 0 | ~ | ~ | ~ | p=1.000 n=6 |
| Symbols | 524,639 | 524,639 | ~ | ~ | ~ | p=1.000 n=6 |
| Types | 178,906 | 178,906 | ~ | ~ | ~ | p=1.000 n=6 |
| Memory used | 462,735k (± 0.01%) | 462,750k (± 0.01%) | ~ | 462,650k | 462,811k | p=0.572 n=6 |
| Parse Time | 3.12s (± 0.81%) | 3.12s (± 0.55%) | ~ | 3.09s | 3.14s | p=0.807 n=6 |
| Bind Time | 1.16s (± 0.35%) | 1.16s (± 1.18%) | ~ | 1.15s | 1.18s | p=0.796 n=6 |
| Check Time | 18.34s (± 0.58%) | 18.35s (± 0.54%) | ~ | 18.16s | 18.44s | p=1.000 n=6 |
| Emit Time | 0.00s | 0.00s (±244.70%) | ~ | 0.00s | 0.01s | p=0.405 n=6 |
| Total Time | 22.63s (± 0.52%) | 22.63s (± 0.44%) | ~ | 22.46s | 22.73s | p=1.000 n=6 |
- node (v18.15.0, x64)
- Compiler-Unions - node (v18.15.0, x64)
- angular-1 - node (v18.15.0, x64)
- mui-docs - node (v18.15.0, x64)
- self-build-src - node (v18.15.0, x64)
- self-build-src-public-api - node (v18.15.0, x64)
- self-compiler - node (v18.15.0, x64)
- ts-pre-modules - node (v18.15.0, x64)
- vscode - node (v18.15.0, x64)
- webpack - node (v18.15.0, x64)
- xstate-main - node (v18.15.0, x64)
| Benchmark | Name | Iterations |
|---|---|---|
| Current | pr | 6 |
| Baseline | baseline | 6 |
Developer Information:
@jakebailey Here are the results of running the top 400 repos comparing main and refs/pull/58495/merge:
Everything looks good!
At first I thought the minimatch break had something with old-fashioned JS constructor function statements that were inferred to be type predicates. But it turned out to be more straightforward. The relevant code is here and all the failures are calls to this function:
var MAX_PATTERN_LENGTH = 1024 * 64
var assertValidPattern = function (pattern) {
if (typeof pattern !== 'string') {
throw new TypeError('invalid pattern')
}
if (pattern.length > MAX_PATTERN_LENGTH) {
throw new TypeError('pattern is too long')
}
}
So I also need to exclude function expressions from inference, not just arrow functions.
This PR doesn't have any linked issues. Please open an issue that references this PR. From there we can discuss and prioritise.
Ironically, inferring assertValidPattern as an assertion predicate is actually correct! But unfortunately it hits the limitation that requires them to be explicitly annotated...
Ironically, inferring
assertValidPatternas an assertion predicate is actually correct! But unfortunately it hits the limitation that requires them to be explicitly annotated...
Right. So far as I'm aware, the algorithm is correct: it will never infer a type assertion predicate that's inaccurate. But there are many situations (methods, arrow functions, function expressions) where it will push you right into TS2775 / TS2776.
@typescript-bot test it @typescript-bot pack this