Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Discussion on --strictOptionalProperties #44421

Open
DanielRosenwasser opened this issue Jun 3, 2021 · 6 comments
Open

Discussion on --strictOptionalProperties #44421

DanielRosenwasser opened this issue Jun 3, 2021 · 6 comments

Comments

@DanielRosenwasser
Copy link
Member

@DanielRosenwasser DanielRosenwasser commented Jun 3, 2021

We've pulled in a new feature called --strictOptionalProperties which sits under the --strict family of flags. If we were to start TypeScript over again, we believe the behavior of strictOptionalProperties would be on by default; however, this strictness option comes at a time when the community is much more mature with lots of existing code.

I've opened up this issue to discuss some broader concerns so that we can ensure that --strictOptionalProperties ships smoothly and so we can hear some feedback from users.

Off the bat, here's a few of my own concerns:

Discoverability of the Break

A user who upgrades TypeScript with --strict on currently has no idea why their code has broken. At best, they will get an error like

Type 'T | U | V | undefined' is not assignable to type 'T | U | V'.
  Type 'undefined' is not assignable to type 'T | U | V'.

We can do better here, which is why I've opened up #44403.

Manual Upgrade Woes

The most permissive thing to do to fix breaks from --strictOptionalProperties is to tack on an | undefined onto every single ?-marked optional property; however, this is incredibly tedious for an existing project.

We'd like to provide some automated tooling to help alleviate this, which is why I've opened up #44419.

Surrounding Community Upgrade Woes

There are really 3 places that are outside most users' control that need to be upgraded to work correctly with strictOptionalProperties:

  • lib.d.ts
  • DefinitelyTyped (@types packages)
  • Libraries shipping their own types

The last one is the hardest to solve; however, the first two are way more automatable, and we can have the core team help with it, but it's definitely time taken away from other work, and that's a delicate tradeoff.

I haven't created an issue to manage this one, but I think it might be worth distributing segments of lib.d.ts and some number of top packages to add | undefined to the definitions and see if that helps. Ideally, automation from #44419 could help. We'd also have to update the lib.dom.d.ts generator to emit | undefined on most optional properties.

I'd like to get @RyanCavanaugh's thoughts on this one.

Other Feedback

I'm curious to hear feedback from users on this one - is it a useful option? Do you feel good about it and its purpose? Did it catch any interesting bugs? Let us know!

@DanielRosenwasser
Copy link
Member Author

@DanielRosenwasser DanielRosenwasser commented Jun 4, 2021

New Errors list from last night #44427 👀

@jakebailey
Copy link
Member

@jakebailey jakebailey commented Jun 4, 2021

Last night I tried updating pyright/pylance to a build of TS that included this to see how it would go. I'll try and sum up my thoughts...

I'm not sure that this check is going to end up being widely usable any time soon; I get loads of messages coming from the types of libraries I don't control, especially from the LSP client library (and spec), where they treat ? as equivalent to undefined. I think that this pattern is very common and unlikely go away.

As for trying to fix our own code, the messaging is definitely bad; I found it very hard to try and locate the actual place I needed to make the change in a large project. I ended up starting tsc in watch mode, opening a file with an error in VS Code, then I see the problems (as VSC only shows errors in open files). Then, either the related diagnostic pointed back to the declaration (so I could jump and add | undefined), or confusingly did not, in which case I had to go-to-def on the error'd expression to figure out what to change.

I'm sure it could be improved to say something like "property had a ? but no undefined", but that is going to push everyone to add | undefined, in which case, is this check helping?

Before I gave up, I still had hundreds of errors to fix. It seemed almost random which properties I needed to change, and I was left with a number of interfaces where some properties had | undefined and some did not, which tells me that at some point in the future, I may use a property in a new way and have to fix them.

I'm not sure I've actually been able to find any bugs with this so far; maybe I'm too inclined to just try and stick | undefined everywhere. I don't think we do any in checks, and only care about truthiness.

I'm pretty surprised that this is on by default; it feels really noisy (far noisier than the not-default noPropertyAccessFromIndexSignature) and I expect to have to disable it when I upgrade. I think it will be very surprising to users with "strict": true to see this enabled.

@OoDeLally
Copy link

@OoDeLally OoDeLally commented Jun 6, 2021

I believe language features should be a right balance between exactness and usability, i.e. a health dose of pragmatism.
With this strictOptionalProperties, I feel like we are sacrificing a lot of usability and readability, just for the purpose of exactness.
From my experience there are very little cases (in fact, I've never encountered any) where I care about whether a field is undefined or missing (and if I ever did, there are ways to assert that).

Now, because I use the strict option, I have to clutter all my types with | undefined.

I guess the issue here stems from the fact that there are many levels of strictness, and because strict is binary, the true value means all possible strictness rules. Maybe there could be several levels.

@fatcerberus
Copy link

@fatcerberus fatcerberus commented Jun 6, 2021

Maybe there could be several levels.

There are - set the individual flags you need. Multiple strict levels + individual options would just be way too much cognitive overhead IMO. If I'm at the point where I'm asking myself "Which level of strictness do I need?" I should probably be researching what exactly my options are anyway.

@fatcerberus
Copy link

@fatcerberus fatcerberus commented Jun 6, 2021

From my experience there are very little cases (in fact, I've never encountered any) where I care about whether a field is undefined or missing (and if I ever did, there are ways to assert that).

Fun fact: When I used to write plain JS, I did "foo" in obj tests all the time. TS forced me out of that habit (very begrudgingly) because it had, until recently, no type-level way to distinguish between ? and | undefined. So while I consider myself pragmatic, I'm hesitant to throw around pragmatism as an excuse here because I never considered the lack of strictOptionalProperties to be very pragmatic 😉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
5 participants