Typescript linting optional vs undefined

Language: Typescript
Rule: S4782
Product: SonarLint VSCode Extension v4.1.0 (not connected)

In stricter typescript projects, specifically using the “exactOptionalPropertyTypes” compiler flag, SonarLint still throws warnings with “Consider removing ‘undefined’ type or ‘?’ specifier, one of them is redundant. [+1 location]” when doing something like the following:

interface ConnData {
  promise?: Promise<unknown> | undefined
}

By standard these syntaxes signify two separate, but potentially convergent, behaviours. The compiler flag simply enforces this convention by throwing errors on compile if the standards aren’t being followed. I’m aware the warning can be suppressed, but ideally SonarLint would disable the warning if the relevant compiler flag is enabled. Ideally the rule would be removed altogether, as the two syntaxes do signify two different behaviours, but the duplicate labelling isn’t necessary if not using the compiler flag, so I can see reasoning either way on that one (though other linters will likely complain if one or the other is removed).

For those unaware, the different behaviours are:

variable?: string // Not required to specify at instantiation, but cannot be declared later if not provided.
variable: string | undefined // Required to specify at instantiation, but can explicitly be set to undefined during/after
variable?: string | undefined // May be omitted at instantiation, and then later updated to other values/undefined

The duplicate labeling isn’t actually required with the compiler flag on in many cases, as typescript is smart enough to cast interfaces without needing both defined as long as the keys match perfectly. If, however, you have extra object keys and want to use something as an interface, both are required to cast the object to a usable interface.

Example A (works fine if one is removed):

interface TestInt {
    id: string;
    name?: string | undefined;
}

const x = {
    id: "1"
} as TestInt;

x.name = "test";
x.name = undefined;

Example B (requires both, removing either ? or undefined causes compiler errors):

interface TestInt {
    id: string;
    name?: string | undefined;
}

const x = {
    id: "1",
    extra: true,
} as TestInt;

x.name = "test";
x.name = undefined;

It’s a rather niche occurrence, but as s it stands currently there are currently valid typescript objects/expected behaviour that throw errors if either side of the declaration is removed with the compiler flag enabled.

Hello @jgh713 ,

Welcome to our Sonar community and thank you for bringing this to our attention!

You’re absolutely right about the TypeScript’s compiler option “exactOptionalPropertyTypes” leading to false positives with S4782. I really appreciate the comprehensive explanation you provided :slight_smile:

To tackle this, I created this ticket, and we’ll do our best to get this fixed as soon as we can.

Best,