-
Notifications
You must be signed in to change notification settings - Fork 13.2k
Description
π Search Terms
"evolving any", "non-null assertion", "compiler api"
π Version & Regression Information
- This changed in version 5.1
β― Playground Link
NOTE: I linked to the typescript-eslint playground just because it both supports // ^? and also provides access to the TS types so you can easily see the issue. You can ofc reproduce this in the TS playground too.
π» Code
declare function foo(): number | undefined
declare function bar(): number
function main1() {
let x;
x = bar();
x = foo();
//^?
let y1 =
// ^?
x;
// ^?
let y2 =
// ^?
x!;
// ^?
let y3 =
// ^?
x as number;
// ^?
}π Actual behavior
declare function foo(): number | undefined
declare function bar(): number
function main1() {
let x;
x = bar();
x = foo();
//^? any β
let y1 =
// ^? number | undefined β
x;
// ^? number | undefined β
let y2 =
// ^? number β
x!;
// ^? number β
let y3 =
// ^? number β
x as number;
// ^? number | undefined β
}π Expected behavior
declare function foo(): number | undefined
declare function bar(): number
function main1() {
let x;
x = bar();
x = foo();
//^? any β
let y1 =
// ^? number | undefined β
x;
// ^? number | undefined β
let y2 =
// ^? number β
x!;
// ^? number | undefined ββββ
let y3 =
// ^? number β
x as number;
// ^? number | undefined β
}Additional information about the issue
Reference: typescript-eslint/typescript-eslint#10334
TypeScript-ESLint has a rule called no-unnecessary-type-assertion which, as the name implies, flags unnecessary type assertions to help keep the code clean.
One of the checks done by the rule involves flagging unnecessary non-null assertions.
The basic logic for this check is "if the type of the thing does not include null | undefined then the non-null assertion is unnecessary".
By "the thing" I am referring to the expression being non-null asserted, eg the x in x!.
In the case of an "evolving any" the type of the variable is shown to be incorrect by the TS APIs.
As shown in the example code (specifically the y2 case) - the type of x is presented as number - even though it should be presented as number | undefined. It appears that for some reason the non-null assertion modifies the type of the variable to remove the | undefined, rather than just emitting a non-nullish type from the non-null assertion expression.
This is made even weirder from the fact that writing x as number behaves correctly and the type of x is correctly presented as number | undefined.
This discrepancy is problematic for our lint rule because it means we currently false-positive on this case because when we query for the type of x it looks non-nullish -- which suggests the non-null assertion is unnecessary. But if the user removes the non-null assertion then the type of x changes to number | undefined and this causes errors.