unconstrained type parameters are consistently checked for {} | null | undefined in strictNullChecks#59059
unconstrained type parameters are consistently checked for {} | null | undefined in strictNullChecks#59059iisaduan wants to merge 8 commits intomicrosoft:mainfrom
{} | null | undefined in strictNullChecks#59059Conversation
|
@typescript-bot pack this |
| > : ^^^^^^^ | ||
| >value : (T & {}) | null | ||
| > : ^^^^^^^^^^^^^^^ | ||
| >value : (T & ({} | null)) | null |
There was a problem hiding this comment.
this seems to be the only weirder/"I may need to fix that" break that happens in the test suite. This test pre-dates #49119, which adds "An unconstrained type parameter is no longer assignable to {}" and was the cause of the original regression that this PR fixes, so the code in this test doesn't do what the original author probably intended.
|
Hey @iisaduan, I've packed this into an installable tgz. You can install it for testing by referencing it in your and then running There is also a playground for this build and an npm module you can use via |
|
@typescript-bot test it |
|
Hey @iisaduan, the results of running the DT tests are ready. Everything looks the same! |
|
@iisaduan Here are the results of running the user tests with tsc comparing Something interesting changed - please have a look. Details
|
|
@iisaduan Here they are:
tscComparison Report - baseline..pr
System info unknown
Hosts
Scenarios
Developer Information: |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@iisaduan Here are the results of running the top 400 repos with tsc comparing Something interesting changed - please have a look. Details
|
…constrainedTypeParameter
|
With this PR, this lint check is necessary, as it was what was causing the self-check to fail earlier https://github.com/microsoft/TypeScript/actions/runs/9751008069/job/26911678446 |
|
So one of the things that no longer works is the following: function f<T, K extends keyof T>(obj: T, key: K) {
return obj[key];
// ~~~
// error! 'obj' is possibly 'null' or 'undefined'.
}One of the reasons we've typically said that this is okay is because f(undefined, "hello");
// ~~~~~~~
// error! Argument of type 'string' is not assignable to parameter of type 'never'.I know @ahejlsberg was considering changing this for other reasons around the time that #56652 was out. Maybe he has some thoughts here or can give some pointers. I think we can fix #50603 well enough without disrupting the behaviors in place, but I'd have to take a deeper look to help out there. |
Thanks for the insight! I think so too, I will fix that. Those test cases looked alright at first, but after you brought the above up, I was reminded that the following is similarish and fine function f<T>(obj: T) {
for (const key in obj) {
obj[key]; // no errors
}
} |
|
@typescript-bot test it |
|
Hey @iisaduan, the results of running the DT tests are ready. Everything looks the same! |
|
@iisaduan Here are the results of running the user tests with tsc comparing Something interesting changed - please have a look. Details
|
|
@iisaduan Here they are:
tscComparison Report - baseline..pr
System info unknown
Hosts
Scenarios
Developer Information: |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@iisaduan Here are the results of running the top 400 repos with tsc comparing Something interesting changed - please have a look. Details
|
|
@DanielRosenwasser interestingly, this is also a current issue (5.5.3, playground) when function f<T extends {} | null | undefined , K extends keyof T>(obj: T, key: K) {
return obj[key];
~~~
!!! error TS18049: 'obj' is possibly 'null' or 'undefined'.
~~~~~~~~
!!! error TS2536: Type 'K' cannot be used to index type '{}'.
} |
{} | null | undefined in strictNullChecks{} | null | undefined in strictNullChecks
|
@typescript-bot test top400 |
|
@iisaduan Here are the results of running the user tests with tsc comparing Something interesting changed - please have a look. Details
|
|
Looks like #50603 is being addressed in #59352 (and I'll comment on that separately there). Meanwhile, in the example function f<T, K extends keyof T>(obj: T, key: K) {
return obj[key]; // Ok
}
function g<T extends {} | null | undefined , K extends keyof T>(obj: T, key: K) {
return obj[key]; // Error, 'obj' is possibly 'null' or 'undefined'.
}the second error really shouldn't be there. As @DanielRosenwasser points out above, for any |
fixes #50603
This behavior is due to a case that was unchecked in #49119. (Relevant summary of 49119:
{}";unknown, which is equivalent toextends {} | null | undefined;The behavior was previously inconsistent, as shown in the cases below (5.5.3 playground):
Implementation:
This PR
TypeFactsreturns for unconstrained parameters. Instead of finding that unconstrained type parameters haveUnknownFacts, we allow unconstrained type parameters to have all facts. SinceUnknownFacts = AllFacts & ~UndefinedOrNull, this change means that unconstrained type parameters now have the possibility to be treated asundefined | nulleven when not explicitly unioned.checkNonNullExpressionConsiderations left
-- in
function f<T, U extends T>,Uis not an unconstrained parameter-- (CFA needed?) to check previously ok cases (see
tests/baselines/reference/isomorphicMappedTypeInference.errors.txt)--
const b = "foo" in obj[key];is no longer okay when we have parameter(obj: T)(seekeyofAndIndexedAccessErrors.txt)