In TypeScript 2.3, we introduced the --strict
flag. The intent of this flag was to "opt in" to the strictest possible subset of TypeScript, along with the implied future breaking changes associated with any further improvements in strictness. As we added new forms of stricter checking, we added opt-out flags so that developers could disable individual aspects of this "strictest" mode.
However, pursuant to our goal of not making overly large breaking changes, we've held off on implementing stricter checking in places where it would cause an infeasibly large number of breaks in exixting codebases. Even developers who opted into --strict
should not find themselves facing hundreds or thousands of new errors during a routine compiler version upgrade.
This has restricted our ability to add certain forms of stricter checking where the desired errors occur in places that are either highly idiomatic, or would require new syntax across a large number of use sites.
For example, we know that including undefined
in the type of array access expressions arr[i]
is a highly-demanded feature, but even a cursory check of existing code shows that this would cause hundreds of errors in almost any codebase.
Another example would be the override
keyword - this is a popular request, but the feature provides very little value without a corresponding ability to require that all overriding methods are declared as such. It would be untenable, even in strict
, to expect people upgrading from version N
to N+0.1
of TypeScript to also insert new override
keywords throughout their codebase.
The proposal is effectively a non-feature -- let's decide to allow adding new forms of strictness that are not part of --strict
. The value provided here is fairly uncontroversial; we simply need to decide how to name and message these features in a way that minimizes user confusion.
How should pedantic flags be named? Several options here:
- Apply a naming convention e.g.
--pedanticNoImplicitStringConversion
- Leave them as "bare" switches, e.g.
--noImplicitStringConversion
, which aren't enabled by default by--strict
- Something else?
Points in favor of the "bare" convention:
- Avoids the appearance of judgmentalism (i.e. "We don't think you should, but okay")
- In the event we find a way to make something the default under
--strict
, the migration path is clearer - Shorter
Points in favor of the "pedantic" convention:
- Makes our opinion on the flag quite clear (i.e. "We don't think you should, but okay")
- Extremely clear that these are not part of
--strict
--strict
exists to turn on all flags starting with strict
, so should --pedantic
exist?
I would argue against doing this. Developers inclined toward the "safest possible" TypeScript will be strongly motivated to turn on such a switch if it exists, and will surely advocate for others to do the same. This will result in future upgrade pain for very little concrete upside.
By definition, we don't think these are switches that can be painlessly enabled, so the expected user experience under --pedantic
would be:
- Upgrade to the next TypeScript version
- Hundreds of new errors appear
- Oh no; are any of these actual breaks, or just new pedantic warnings?
- Go read the release blog post, find out which new pedantic flags were added
- Disable the new pedantic rules
- Get the build to clean again
- Possibly re-enable each pedantic flag on a case-by-case basis
If we don't have --pedantic
, developers who want the "safest possible" experience would encounter this workflow:
- Upgrade to the next TypeScript version
- Get the build to clean again
- Go read the release blog post, find out which new pedantic flags were added
- Possibly enable each pedantic flag on a case-by-case basis
This is just a shorter version of the steps under --pedantic
; nothing of value was gained by having the flag exist.
Note: Some of these lack canonical issues; flag names are extremely open to bikeshedding
--noImplicitBooleanCoercion
#7746--noImplicitStringCoercion
#7989--pessimisticLookups
#13778--pessimisticControlFlow
#9998 ??--noImplicitPropertyLookup
to turn off allowingexpr.prop
whenexpr
just has a string index signature--noImplicitOverride
ifoverride
were to exist--noAnyPropertyAccess
variant ofsafeAny
--noUntypedFunctionCalls
untyped function calls are a huge trap and should maybe just be disallowed under--strict
We should still take care to implement these in a way that doesn't meaningfully explode the configuration space -- none of these rules above would change subtype or assignability relations, for example, so could be safely implemented without needing to ensure compat with existing type definitions.
I disagree with your statement that it's less effort just because the text of your list is shorter.
First off, lots of people have multiple projects and CI running for them. It's quite easy to have both a
strict
build and apedantic
build. You don't requirepedantic
to succeed, but you use it as an automated bit of information that things have changed. It does not require staying on top of TypeScript, which not everybody does, because it's not the main development language for everyone.It's easy to go back from
pedantic
tostrict
, it's not so easy to follow all the releases of all the tools you use. So I would say do go for apedantic
and let people discover new flags automatically.To echo your lists.
With pedantic and a proper CI setup:
Without: